diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7c3dcb0e7..3bf45997e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing -If you would like to contribute to the development of the ONE simulator, please fork us on GitHub and send your contributions as pull requests. +If you would like to contribute to the development of the ONE simulator, please fork us on GitHub and send your contributions as pull requests. If you are not sure where to start, new tests are always very welcome! Bugfixes are also highly appreciated. @@ -10,4 +10,4 @@ If you want to add new features, there are some things to take into consideratio * If the new feature requires changes to existing classes, make sure the feature is generic and shared by many use cases. * In particular one should avoid features that slow down simulation even when the new feature is not in use (e.g., if it requires checks for each simulation round) -When doing contributions, please try to follow the coding style of the existing code. \ No newline at end of file +When doing contributions, please try to follow the coding style of the existing code. diff --git a/HISTORY.txt b/HISTORY.txt index 0e90d4166..10fa566c2 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -1,205 +1,205 @@ -HISTORY - -This document describes the main changes between each release version. - - -Version 1.6.0 (Oct 2015) - - Migrated code to github: https://github.com/akeranen/the-one - - New interface module: DistanceCapacityInterface for modeling - interfaces where transfer capacity depends on the distance between - nodes (see also example_settings/wifi-interface.txt) - - New report module: BufferOccupancyReport - - New movement modules: RandomDirection and ModifiedRandomDirection - - moved all example settings except default_settings.txt to example_settings - - Lots of small bug fixes - - -Version 1.5.0 (Dec 2011 - Nov 2013) - - New movement models - - GridLocation for static grid formations - - LinearMovement for nodes moving on a line - - Path-based external movement model and reader (ExternalPathMovement) - - New router modules - - WaveRouter for forwarding messages in waves - - LifeRouter for "Conway's game of life"-kind of routing - - ProphetV2Router with updated PRoPHET algorithm (by Samo Grasic) - - New Report modules: MessageCopyCountReport & MessageAvailabilityReport - (and analyzing/plotting scripts for them) - - Generic energy awareness feature for all routing modules - - Message Transfer Accept Policy for defining which messages and from who - the nodes should accept for transfers (with any routing module) - - Configuration settings improvements - - Ability to define ranges as setting values - - Ability to define arithmetic expressions as setting values - - Default-getters for various settings types - - Optimization option to simulate connections only once (see World class) - - Sub-namespace support - - Group-specific network interface related settings (e.g., activePeriods - and scanInterval) are now in "net" sub-namespace - - GUI fixes & updates - - Offset to playfield view and dynamic scaling of distance reference bar - - Option to disable (by default) the node name string - - Autorefresh-feature and keeping the expanded-state to routing info window - - Showing of radio coverages, connections and message count is configurable - - New GUI features - - Focus nodes by clicking on the playfield (see "Playfield options" menu) - - GUI node filters feature and one message based filter (see "Tools" menu) - - Bugfixes - - Scan intervals work also without MessageCommunicationBus; - thanks to Matthew Orlinski - - Connections are properly cleared when ActivenessHandler is used - - MaxProp doesn't send messages to hosts that have already received the - message even if they have then deleted it - - Fix to scanning intervals (works with only the 1st interface though) - - Fixed cellSizeMultiplier in ConnectivityGrid class - - Message blacklisting for messages that have been rejected by application - - Typo fix to initialEnergy setting (need to update config files using this) - - Refactoring (may break some third party code) - - Moved utility classes to util and routing.util packages - - Renamed getOldestMessage method to getNextMessageToRemove in ActiveRouter - - -Version 1.4.1 (31 Jan 2011) - - Bugfixes - - External connectivity traces now properly clear connections; thanks to CS - - InterferenceLimitedInterface speeds are updated; thanks to Jad Makhlouta - - CarMovement reads speed properly from settings - - Warmup time fix to connectivity reports - - Fixed initial location (was off by one stop) in MapRoute movement model - - dieselnetConverter.pl supports now also exponent format in the input data - - GUI fixes - - Fixed window resize issue and using spinner instead of dropdown for zoom - levels; thanks to PJ - - Set of javadoc, style, and other small fixes - - -Version 1.4.0 (18 Mar 2010) - - Added the possibility for each node having multiple interfaces - * Requires changes to the configuration files, see default_settings.txt - - New/improved routing algorithms - * added parametrization for MaxProp (default alpha=1) - * added Prophet and Maxprop routing algorithm versions that - take timescale as a parameter, and estimate the needed routing algorithm - parameters based on that - * see Karvo and Ott, Time Scales and Delay-Tolerant Routing Protocols, - CHANTS 2008, for more information. - * added new (unrealistic) EpidemicOracleRouter that transfers messages - immediately and deletes all replicas from buffers when the message is - delivered - * added maximum meeting probability set size support for MaxProp to improve - its performance in scenarios with many nodes - - Added MessageReport class for reporting message deliveries, - CreatedMessagesReport for message creations and EventLogReport for - reporting everything (in a StandardEventsReader-compatible format) - - Added application layer - * applications can be created by extending the Application class - * multiple applications can run in the nodes - * report modules can register for application events - * see PingApplication and PingAppReporter for an example - - Added ClusterMovement for creating clusters of nodes and LinearFormation - for lines of nodes - - ExternalMovementReader supports comment lines (starting with "#") - - "Delete all" message event and support for this in StandardEventsReader - - Possibility to choose first route stop for MapRouteMovement - - Added new message event generators: OneFromEachMessageGenerator and - OneToEachMessageGenerator - - Added time range setting to MessageEventGenerator - - GUI improvements - * highlighting of pause-events to EventLogPanel - * GUI starts paused by default - * hh:mm:ss display for simulation time (right-click the simulation time) - - Improved and new analysis scripts - * added "log", "total", and "index" options for the ccdfPlotter.pl - * added getStatsAverages.pl - - Bugfixes - * host range checking in MessageEventGenerator - * command line option -b doesn't require range anymore - - - -Version 1.3.0 (19 Jan 2009) -- New Features - - ModuleCommunicationBus for sharing information between different - (types of) modules - - EnergyAwareRouter demonstrating energy awareness possibilities and use of - the ModuleCommunicationBus - - EnergyLevelReport for reporting the energy levels - - ConnectivityONEReport class for generating connectivity traces - that can be read using the StandardEventsReader -- Enhancements - - Any number of input config files supported - - Batch mode supports run index ranges (can start from any index) - - small change in the command line syntax; see README for details - - MessageEventGenerator supports message creation time and destination - host ranges - - NetworkLayer has configurable scanning intervals - - ExternalEventsQueue can be configured like all the other event - generators (though the old way is still supported too) - - ccdfPlotter script has better help and can now also create CDFs -- New toolkit scripts - - messageLocationAnimator for creating GIF animations out of - MessageLocation reports - - dieselNetConverter for converting DieselNet traces into ONE - mobility traces - - getAverages for counting averages out of different time-stamped reports - - splotEnergy for creating 3D plots from EnergyLevel reports -- Fixed bugs in - - handling of incoming messages with expired TTL - - report directory creation; thanks to STARpio - - BusTravellerMovement incState; thanks to Mehedi Bakht - - MaxProp calcTreshold; thanks to Vasco Soares and STARpio - - -Version 1.2.0 (25 Aug 2008) -- New movement model (framework): Working Day Movement - - see WDM_conf_help.txt for configuration help - - sample configuration files can be found from the wdm_settings folder - - for information about the model, see our paper at - http://www.netlab.tkk.fi/tutkimus/distance/papers/ - 2008-mobmod-working-day-model.pdf -- A "stationary movement model" StationaryMovement. - - useful for running simulations with only connectivity trace input - - createCircles.pl script for easily creating suitable configuration - files for this movement model - - -Version 1.1.0 (6 May 2008) -- External Events Interface which allows event generator classes that - can generate external events (such as creating new messages or - setting up and tearing down connections). See EventQueueHandler - class for details. - - due to the EEI, some API changes (in e.g., - createNewMessage method) - - external events file feature is now part of the new interface - - MessageEventGenerator class for generating uniformly - distributed message creation patterns - - new event: ConnectionEvent (supported by StandardEventsReader) -- Configurable message queue modes (random and FIFO) -- Option to automatically delete messages that are already delivered - to the final recipient -- Small change in the ordering of checks whether transfer has - already succeeded when the connection has gone down -- Connection class has now getTransferDoneTime method -- Settings class can validate range settings (assertValidRange) -- Classes that need to reset static fields between batch runs can - register to the "resetting service" at DTNSim class - (registerForReset) -- Experimental "update scheduling" functionality that can be used to - dynamically insert "update points" between time steps for higher - precision simulations -- DTN2 connectivity (requires JDK 6 or higher) -- Generic property adding feature for Message class (addProperty, - getProperty and updateProperty) - - SprayAndWait router uses this now for the copy count -- New tests - - -Version 1.0.1 (24 February 2008) -- New warm up feature for the report modules that allows ignoring - events and messages that were created during a configurable warm - up time. -- New routing module: First Contact - - -Version 1.0.0 (27 November 2007) -- First official public release +HISTORY + +This document describes the main changes between each release version. + + +Version 1.6.0 (Oct 2015) + - Migrated code to github: https://github.com/akeranen/the-one + - New interface module: DistanceCapacityInterface for modeling + interfaces where transfer capacity depends on the distance between + nodes (see also example_settings/wifi-interface.txt) + - New report module: BufferOccupancyReport + - New movement modules: RandomDirection and ModifiedRandomDirection + - moved all example settings except default_settings.txt to example_settings + - Lots of small bug fixes + + +Version 1.5.0 (Dec 2011 - Nov 2013) + - New movement models + - GridLocation for static grid formations + - LinearMovement for nodes moving on a line + - Path-based external movement model and reader (ExternalPathMovement) + - New router modules + - WaveRouter for forwarding messages in waves + - LifeRouter for "Conway's game of life"-kind of routing + - ProphetV2Router with updated PRoPHET algorithm (by Samo Grasic) + - New Report modules: MessageCopyCountReport & MessageAvailabilityReport + (and analyzing/plotting scripts for them) + - Generic energy awareness feature for all routing modules + - Message Transfer Accept Policy for defining which messages and from who + the nodes should accept for transfers (with any routing module) + - Configuration settings improvements + - Ability to define ranges as setting values + - Ability to define arithmetic expressions as setting values + - Default-getters for various settings types + - Optimization option to simulate connections only once (see World class) + - Sub-namespace support + - Group-specific network interface related settings (e.g., activePeriods + and scanInterval) are now in "net" sub-namespace + - GUI fixes & updates + - Offset to playfield view and dynamic scaling of distance reference bar + - Option to disable (by default) the node name string + - Autorefresh-feature and keeping the expanded-state to routing info window + - Showing of radio coverages, connections and message count is configurable + - New GUI features + - Focus nodes by clicking on the playfield (see "Playfield options" menu) + - GUI node filters feature and one message based filter (see "Tools" menu) + - Bugfixes + - Scan intervals work also without MessageCommunicationBus; + thanks to Matthew Orlinski + - Connections are properly cleared when ActivenessHandler is used + - MaxProp doesn't send messages to hosts that have already received the + message even if they have then deleted it + - Fix to scanning intervals (works with only the 1st interface though) + - Fixed cellSizeMultiplier in ConnectivityGrid class + - Message blacklisting for messages that have been rejected by application + - Typo fix to initialEnergy setting (need to update config files using this) + - Refactoring (may break some third party code) + - Moved utility classes to util and routing.util packages + - Renamed getOldestMessage method to getNextMessageToRemove in ActiveRouter + + +Version 1.4.1 (31 Jan 2011) + - Bugfixes + - External connectivity traces now properly clear connections; thanks to CS + - InterferenceLimitedInterface speeds are updated; thanks to Jad Makhlouta + - CarMovement reads speed properly from settings + - Warmup time fix to connectivity reports + - Fixed initial location (was off by one stop) in MapRoute movement model + - dieselnetConverter.pl supports now also exponent format in the input data + - GUI fixes + - Fixed window resize issue and using spinner instead of dropdown for zoom + levels; thanks to PJ + - Set of javadoc, style, and other small fixes + + +Version 1.4.0 (18 Mar 2010) + - Added the possibility for each node having multiple interfaces + * Requires changes to the configuration files, see default_settings.txt + - New/improved routing algorithms + * added parametrization for MaxProp (default alpha=1) + * added Prophet and Maxprop routing algorithm versions that + take timescale as a parameter, and estimate the needed routing algorithm + parameters based on that + * see Karvo and Ott, Time Scales and Delay-Tolerant Routing Protocols, + CHANTS 2008, for more information. + * added new (unrealistic) EpidemicOracleRouter that transfers messages + immediately and deletes all replicas from buffers when the message is + delivered + * added maximum meeting probability set size support for MaxProp to improve + its performance in scenarios with many nodes + - Added MessageReport class for reporting message deliveries, + CreatedMessagesReport for message creations and EventLogReport for + reporting everything (in a StandardEventsReader-compatible format) + - Added application layer + * applications can be created by extending the Application class + * multiple applications can run in the nodes + * report modules can register for application events + * see PingApplication and PingAppReporter for an example + - Added ClusterMovement for creating clusters of nodes and LinearFormation + for lines of nodes + - ExternalMovementReader supports comment lines (starting with "#") + - "Delete all" message event and support for this in StandardEventsReader + - Possibility to choose first route stop for MapRouteMovement + - Added new message event generators: OneFromEachMessageGenerator and + OneToEachMessageGenerator + - Added time range setting to MessageEventGenerator + - GUI improvements + * highlighting of pause-events to EventLogPanel + * GUI starts paused by default + * hh:mm:ss display for simulation time (right-click the simulation time) + - Improved and new analysis scripts + * added "log", "total", and "index" options for the ccdfPlotter.pl + * added getStatsAverages.pl + - Bugfixes + * host range checking in MessageEventGenerator + * command line option -b doesn't require range anymore + + + +Version 1.3.0 (19 Jan 2009) +- New Features + - ModuleCommunicationBus for sharing information between different + (types of) modules + - EnergyAwareRouter demonstrating energy awareness possibilities and use of + the ModuleCommunicationBus + - EnergyLevelReport for reporting the energy levels + - ConnectivityONEReport class for generating connectivity traces + that can be read using the StandardEventsReader +- Enhancements + - Any number of input config files supported + - Batch mode supports run index ranges (can start from any index) + - small change in the command line syntax; see README for details + - MessageEventGenerator supports message creation time and destination + host ranges + - NetworkLayer has configurable scanning intervals + - ExternalEventsQueue can be configured like all the other event + generators (though the old way is still supported too) + - ccdfPlotter script has better help and can now also create CDFs +- New toolkit scripts + - messageLocationAnimator for creating GIF animations out of + MessageLocation reports + - dieselNetConverter for converting DieselNet traces into ONE + mobility traces + - getAverages for counting averages out of different time-stamped reports + - splotEnergy for creating 3D plots from EnergyLevel reports +- Fixed bugs in + - handling of incoming messages with expired TTL + - report directory creation; thanks to STARpio + - BusTravellerMovement incState; thanks to Mehedi Bakht + - MaxProp calcTreshold; thanks to Vasco Soares and STARpio + + +Version 1.2.0 (25 Aug 2008) +- New movement model (framework): Working Day Movement + - see WDM_conf_help.txt for configuration help + - sample configuration files can be found from the wdm_settings folder + - for information about the model, see our paper at + http://www.netlab.tkk.fi/tutkimus/distance/papers/ + 2008-mobmod-working-day-model.pdf +- A "stationary movement model" StationaryMovement. + - useful for running simulations with only connectivity trace input + - createCircles.pl script for easily creating suitable configuration + files for this movement model + + +Version 1.1.0 (6 May 2008) +- External Events Interface which allows event generator classes that + can generate external events (such as creating new messages or + setting up and tearing down connections). See EventQueueHandler + class for details. + - due to the EEI, some API changes (in e.g., + createNewMessage method) + - external events file feature is now part of the new interface + - MessageEventGenerator class for generating uniformly + distributed message creation patterns + - new event: ConnectionEvent (supported by StandardEventsReader) +- Configurable message queue modes (random and FIFO) +- Option to automatically delete messages that are already delivered + to the final recipient +- Small change in the ordering of checks whether transfer has + already succeeded when the connection has gone down +- Connection class has now getTransferDoneTime method +- Settings class can validate range settings (assertValidRange) +- Classes that need to reset static fields between batch runs can + register to the "resetting service" at DTNSim class + (registerForReset) +- Experimental "update scheduling" functionality that can be used to + dynamically insert "update points" between time steps for higher + precision simulations +- DTN2 connectivity (requires JDK 6 or higher) +- Generic property adding feature for Message class (addProperty, + getProperty and updateProperty) + - SprayAndWait router uses this now for the copy count +- New tests + + +Version 1.0.1 (24 February 2008) +- New warm up feature for the report modules that allows ignoring + events and messages that were created during a configurable warm + up time. +- New routing module: First Contact + + +Version 1.0.0 (27 November 2007) +- First official public release diff --git a/LICENSE.txt b/LICENSE.txt index b03cc8a8b..77b0aee29 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,628 +1,628 @@ -This program (the ONE) is released under the GPLv3 (see details below). -The included vector map data of the downtown Helsinki area is not GPL'ed -and it should be used only with the ONE simulator -(Copyright: Maanmittauslaitos, 2007). - ------------------------------------------------------------------------- - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS +This program (the ONE) is released under the GPLv3 (see details below). +The included vector map data of the downtown Helsinki area is not GPL'ed +and it should be used only with the ONE simulator +(Copyright: Maanmittauslaitos, 2007). + +------------------------------------------------------------------------ + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS diff --git a/README.txt b/README.txt index 900dd4354..1716269a7 100644 --- a/README.txt +++ b/README.txt @@ -1,723 +1,723 @@ -The ONE v1.6.0 - Readme -======================= - -The ONE is a Opportunistic Network Environment simulator which provides a -powerful tool for generating mobility traces, running DTN messaging -simulations with different routing protocols, and visualizing both -simulations interactively in real-time and results after their completion. - - -Quick start -=========== - -Compiling ---------- - -You can compile ONE from the source code using the included compile.bat -script. That should work both in Windows and Unix/Linux environment with -Java 6 JDK or later. - -If you want to use Eclipse for compiling the ONE, since version 1.1.0 you need -to include some jar libraries in the project's build path. The libraries are -located in the lib folder. To include them in Eclipse, assuming that you have -an Eclipse Java project whose root folder is the folder where you extracted -the ONE, do the following: - -select from menus: Project -> Properties -> Java Build Path -Go to "Libraries" tab -Click "Add JARs..." -Select "DTNConsoleConnection.jar" under the "lib" folder -Add the "ECLA.jar" the same way -Press "OK". - -Now Eclipse should be able to compile the ONE without warnings. - - -Running -------- - -ONE can be started using the included one.bat (for Windows) or one.sh (for -Linux/Unix) script. Following examples assume you're using the Linux/Unix -script (just replace "./one.sh" with "one.bat" for Windows). - -Synopsis: -./one.sh [-b runcount] [conf-files] - -Options: - -b Run simulation in batch mode. Doesn't start GUI but prints -information about the progress to terminal. The option must be followed -by the number of runs to perform in the batch mode or by a range of runs -to perform, delimited with a colon (e.g, value 2:4 would perform runs 2, -3 and 4). See section "Run indexing" for more information. - -Parameters: - conf-files: The configuration file names where simulation parameters -are read from. Any number of configuration files can be defined and they are -read in the order given in the command line. Values in the later config files -override values in earlier config files. - - -Configuring -=========== - -All simulation parameters are given using configuration files. These files -are normal text files that contain key-value pairs. Syntax for most of the -variables is: -Namespace.key = value - -I.e., the key is (usually) prefixed by a namespace, followed by a dot, and -then key name. Key and value are separated by equals-sign. Namespaces -start with capital letter and both namespace and keys are written in -CamelCase (and are case sensitive). Namespace defines (loosely) the part -of the simulation environment where the setting has effect on. Many, but -not all, namespaces are equal to the class name where they are read. -Especially movement models, report modules and routing modules follow this -convention. In some cases the namespace is defined by the user: e.g., with -network interfaces user can pick up any idenfitier, define interface specific -settings in that namespace, and give the name of the namespace when -configuring which interface each group should use. - -Numeric values use '.' as the decimal separator and can be suffixed with -kilo (k) mega (M) or giga (G) suffix. Boolean settings accept "true", -"false", "0", and "1" as values. - -Many settings define paths to external data files. The paths can be relative -or absolute but the directory separator must be '/' in both Unix and Windows -environment. - -Some variables contain comma-separated values, and for them the syntax is: -Namespace.key = value1, value2, value3, etc. - -For run-indexed values the syntax is: -Namespace.key = [run1value; run2value; run3value; etc] -I.e., all values are given in brackets and values for different run are -separated by semicolon. Each value can also be a comma-separated value. -For more information about run indexing, go to section "Run indexing". - -Setting files can contain comments too. A comment line must start with "#" -character. Rest of the line is skipped when the settings are read. This can -be also useful for disabling settings easily. - -Some values (scenario and report names at the moment) support "value -filling". With this feature, you can construct e.g., scenario name -dynamically from the setting values. This is especially useful when using -run indexing. Just put setting key names in the value part prefixed and -suffixed by two percent (%) signs. These placeholders are replaces by the -current setting value from the configuration file. See the included -snw_comparison_settings.txt for an example. - -File "default_settings.txt", if exists, is always read and the other -configuration files given as parameter can define more settings or override -some (or even all) settings in the previous files. The idea is that -you can define in the earlier files all the settings that are common for -all the simulations and run different, specific, simulations using -different configuration files. - - -Run indexing ------------- - -Run indexing is a feature that allows you to run large amounts of -different configurations using only single configuration file. The idea is -that you provide an array of settings (using the syntax described above) -for the variables that should be changed between runs. For example, if you -want to run the simulation using five different random number generator -seeds for movement models, you can define in the settings file the -following: - -MovementModel.rngSeed = [1; 2; 3; 4; 5] - -Now, if you run the simulation using command: - -./one.sh -b 5 my_config.txt - -you would run first using seed 1 (run index 0), then another run using -seed 2, etc. Note that you have to run it using batch mode (-b option) if -you want to use different values. Without the batch mode flag the first -parameter (if numeric) is the run index to use when running in GUI mode. - -Run indexes wrap around: used value is the value at index (runIndex % -arrayLength). Because of wrapping, you can easily run large amount of -permutations easily. For example, if you define two key-value pairs: - -key1 = [1; 2] -key2 = [a; b; c] - -and run simulation using run-index count 6, you would get all permutations -of the two values (1,a; 2,b; 1,c; 2,a; 1,b; 2,c). This naturally works -with any amount of arrays. Just make sure that the smallest common -nominator of all array sizes is 1 (e.g., use arrays whose sizes are primes) --- unless you don't want all permutations but some values should be -paired. - - -Movement models ---------------- - -Movement models govern the way nodes move in the simulation. They provide -coordinates, speeds and pause times for the nodes. The basic installation -contains, e.g., random waypoint, map based movement, shortest path map based -movement, map route movement, and external movement. All these models, except -external movement, have configurable speed and pause time distributions. A -minimum and maximum values can be given and the movement model draws -uniformly distributed random values that are within the given range. Same -applies for pause times. In external movement model the speeds and pause -times are interpreted from the given data. - -When a node uses the random waypoint movement model (RandomWaypoint), it is -given a random coordinate in the simulation area. Node moves directly to the -given destination at constant speed, pauses for a while, and then gets a new -destination. This continues throughout the simulations and nodes move along -these zig-zag paths. - -Map-based movement models constrain the node movement to predefined paths. -Different types of paths can be defined and one can define valid paths for -all node groups. This way e.g., cars can be prevented from driving indoors or -on pedestrian paths. - -The basic map-based movement model (MapBasedMovement) initially distributes -the nodes between any two adjacent (i.e., connected by a path) map nodes and -then nodes start moving from adjacent map node to another. When node reaches -the next map node, it randomly selects the next adjacent map node but chooses -the map node where it came from only if that is the only option (i.e., avoids -going back to where it came from). Once node has moved trough 10-100 map -nodes, it pauses for a while and then starts moving again. - -The more sophisticated version of the map-based movement model -(ShortestPathMapBasedMovement) uses Dijkstra's shortest path algorithm to -find its way trough the map area. Once a node reaches its destination, and -has waited for the pause time, a new random map node is chosen and node moves -there using the shortest path that can be taken using only valid map nodes. - -For the shortest path based movement models, map data can also contain Points -Of Interest (POIs). Instead of selecting any random map node for the next -destination, the movement model can be configured to give a POI belonging to -a certain POI group with a configurable probability. There can be unlimited -amount of POI groups and all groups can contain any amount of POIs. All node -groups can have different probabilities for all POI groups. POIs can be used -to model e.g., shops, restaurants and tourist attractions. - -Route based movement model (MapRouteMovement) can be used to model nodes that -follow certain routes, e.g. bus or tram lines. Only the stops on the route -have to be defined and then the nodes using that route move from stop to stop -using shortest paths and stop on the stops for the configured time. - -All movement models can also decide when the node is active (moves and can be -connected to) and when not. For all models, except for the external movement, -multiple simulation time intervals can be given and the nodes in that group -will be active only during those times. - -All map-based models get their input data using files formatted with a subset -of the Well Known Text (WKT) format. LINESTRING and MULTILINESTRING -directives of WKT files are supported by the parser for map path data. For -point data (e.g. for POIs), also the POINT directive is supported. Adjacent -nodes in a (MULTI)LINESTRING are considered to form a path and if some lines -contain some vertex(es) with exactly the same coordinates, the paths are -joined from those places (this is how you create intersections). WKT files -can be edited and generated from real world map data using any suitable -Geographic Information System (GIS) program. The map data included in the -simulator distribution was converted and edited using the free, Java based -OpenJUMP GIS program. - -Different map types are defined by storing the paths belonging to different -types to different files. Points Of Interest are simply defined with WKT -POINT directive and POI groups are defined by storing all POIs belonging to a -certain group in the same file. All POIs must also be part of the map data so -they are accessible using the paths. Stops for the routes are defined with -LINESTRING and the stops are traversed in the same order they appear in the -LINESTRING. One WKT file can contain multiple routes and they are given to -nodes in the same order as they appear in the file. - -The experimental movement model that uses external movement data -(ExternalMovement) reads timestamped node locations from a file and moves the -nodes in the simulation accordingly. See javadocs of ExternalMovementReader -class from input package for details of the format. A suitable, experimental -converter script (transimsParser.pl) for TRANSIMS data is included in the -toolkit folder. - -The movement model to use is defined per node group with the "movementModel" -setting. Value of the setting must be a valid movement model class name from -the movement package. Settings that are common for all movement models are -read in the MovementModel class and movement model specific settings are read -in the respective classes. See the javadoc documentation and example -configuration files for details. - -Routing modules and message creation ------------------------------------- - -Routing modules define how the messages are handled in the simulation. Six -basic active routing modules (First Contact, Epidemic, Spray and Wait, Direct -delivery, PRoPHET and MaxProp) and also a passive router for external routing -simulation are included in the package. The active routing modules are -implementations of the well known routing algorithms for DTN routing. There -are also variants of these models and couple of different models included in -the latest versions. See the classes in the routing package for details. - -Passive router is made especially for interacting with other (DTN) routing -simulators or running simulations that don't need any routing functionality. -The router doesn't do anything unless commanded by external events. These -external events are provided to the simulator by a class that implements the -EventQueue interface. - -There are two basic classes that can be used as a source of message events: -ExternalEventsQueue and MessageEventGenerator. The former can read events -from a file that can be created by hand, with a suitable script (e.g., -createCreates.pl script in the toolkit folder), or by converting e.g., -dtnsim2's output to suitable form. See StandardEventsReader class from input -package for details of the format. MessageEventGenerator is a simple message -generator class that creates uniformly distributed message creation patterns -with configurable message creation interval, message size and -source/destination host ranges. More specific messaging scenarios can be -created with MessageBurstGenerator, and One{From,To}EachMessageGenerator -classes. See javadocs for details. - -The toolkit folder contains an experimental parser script (dtnsim2parser.pl) -for dtnsim2's output (there used to be a more capable Java-based parser but -it was discarded in favor of this more easily extendable script). The script -requires a few patches to dtnsim2's code and those can be found from the -toolkit/dtnsim2patches folder. - -The routing module to use is defined per node group with the setting -"router". All routers can't interact properly (e.g., PRoPHET router can only -work with other PRoPHET routers) so usually it makes sense to use the same -(or compatible) router for all groups. - -Reports -------- - -Reports can be used to create summary data of simulation runs, detailed data -of connections and messages, files suitable for post-processing using e.g., -Graphviz (to create graphs) and also to interface with other programs. See -javadocs of report-package classes for details. - -There can be any number of reports for any simulation run and the number of -reports to load is defined with "Report.nrofReports" setting. Report class -names are defined with "Report.reportN" setting, where N is an integer value -starting from 1. The values of the settings must be valid report class names -from the report package. The output directory of all reports (which can be -overridden per report class with the "output" setting) must be defined with -Report.reportDir -setting. If no "output" setting is given for a report -class, the resulting report file name is "ReportClassName_ScenarioName.txt". - -All reports have many configurable settings which can be defined using -ReportClassName.settingKey -syntax. See javadocs of Report class and specific -report classes for details (look for "setting id" definitions). - -Host groups ------------ - -A host group is group of hosts (nodes) that shares movement and routing -module settings. Different groups can have different values for the settings -and this way they can represent different types of nodes. Base settings can -be defined in the "Group" namespace and different node groups can override -these settings or define new settings in their specific namespaces (Group1, -Group2, etc.). - -The settings ------------- - -There are plenty of settings to configure; more than is meaningful to -present here. See javadocs of especially report, routing and movement -model classes for details. See also included settings files for examples. -Perhaps the most important settings are the following. - - -Scenario settings: ---- - -Scenario.name -Name of the scenario. All report files are by default prefixed with this. - -Scenario.simulateConnections -Should connections be simulated. If you're only interested in movement -modeling, you can disable this to get faster simulation. Usually you want -this to be on. - -Scenario.updateInterval -How many seconds are stepped on every update. Increase this to get faster -simulation, but then you'll lose some precision. Values from 0.1 to 2 are good -for simulations. - -Scenario.endTime -How many simulated seconds to simulate. - -Scenario.nrofHostGroups -How many hosts group are present in the simulation. - - -Interface settings (used to define the possible interfaces the nodes can have) ---- - -type -What class (from the interfaces-directory) is used for this interface - -The remaining settings are class-specific. Can be for example: - -transmitRange -Range (meters) of the interface. - -transmitSpeed -Transmit speed of the interface (bytes per second). - - -Host group settings (used in Group or GroupN namespace): ---- - -groupID -Group's identifier (a string or a character). Used as the prefix of host -names that are shown in the GUI and reports. Host's full name is -groupID+networkAddress. - -nrofHosts -Number of hosts in this group. - -nrofInterfaces -Number of interfaces this the nodes of this group use - -interfaceX -The interface that should be used as the interface number X - -movementModel -The movement model all hosts in the group use. Must be a valid class (one -that is a subclass of MovementModel class) name from the movement package. - -waitTime -Minimum and maximum (two comma-separated decimal values) of the wait time -interval (seconds). Defines how long nodes should stay in the same place -after reaching the destination of the current path. A new random value within -the interval is used on every stop. Default value is 0,0. - -speed -Minimum and maximum (two comma-separated decimal values) of the speed -interval (m/s). Defines how fast nodes move. A new random value is used on -every new path. Default value is 1,1. - -bufferSize -Size of the nodes' message buffer (bytes). When the buffer is full, node can't -accept any more messages unless it drops some old messages from the buffer. - -router -Router module which is used to route messages. Must be a valid class -(subclass of MessageRouter class) name from routing package. - -activeTimes -Time intervals (comma-separated simulated time value tuples: start1, end1, -start2, end2, ...) when the nodes in the group should be active. If no -intervals are defined, nodes are active all the time. - -msgTtl -Time To Live (simulated minutes) of the messages created by this host group. -Nodes (with active routing module) check every one minute whether some of -their messages' TTLs have expired and drop such messages. If no TTL is -defined, infinite TTL is used. - - -Group and movement model specific settings (only meaningful for certain -movement models): - -pois -Points Of Interest indexes and probabilities (comma-separated -index-probability tuples: poiIndex1, poiProb1, poiIndex2, poiProb2, ... ). -Indexes are integers and probabilities are decimal values in the range of -0.0-1.0. Setting defines the POI groups where the nodes in this host group -can choose destinations from and the probabilities for choosing a certain POI -group. For example, a (random) POI from the group defined in the POI file1 -(defined with PointsOfInterest.poiFile1 setting) is chosen with the -probability poiProb1. If the sum of all probabilities is less than 1.0, a -probability of choosing any random map node for the next destination is (1.0 -- theSumOfProbabilities). Setting can be used only with -ShortestPathMapBasedMovement -based movement models. - -okMaps -Which map node types (refers to map file indexes) are OK for the group -(comma-separated list of integers). Nodes will not travel trough map nodes -that are not OK for them. As default, all map nodes are OK. Setting can be -used with any MapBasedMovent -based movement model. - -routeFile -If MapRouteMovement movement model is used, this setting defines the route -file (path) where the route is read from. Route file should contain -LINESTRING WKT directives. Each vertex in a LINESTRING represents one stop -on the route. - -routeType -If MapRouteMovement movement model is used, this setting defines the routes -type. Type can be either circular (value 1) or ping-pong (value 2). See -movement.map.MapRoute class for details. - - -Movement model settings: ---- - -MovementModel.rngSeed -The seed for all movement models' random number generator. If the seed and -all the movement model related settings are kept the same, all nodes should -move the same way in different simulations (same destinations and speed & -wait time values are used). - -MovementModel.worldSize -Size of the simulation world in meters (two comma separated values: -width, height). - -PointsOfInterest.poiFileN -For ShortestPathMapBasedMovement -based movement models, this setting defines -the WKT files where the POI coordinates are read from. POI coordinates are -defined using the POINT WKT directive. The "N" in the end of the setting must -be a positive integer (i.e., poiFile1, poiFile2, ...). - -MapBasedMovement.nrofMapFiles -How many map file settings to look for in the settings file. - -MapBasedMovement.mapFileN -Path to the Nth map file ("N" must be a positive integer). There must be at -least nrofMapFiles separate files defined in the configuration files(s). All -map files must be WKT files with LINESTRING and/or MULTILINESTRING WKT -directives. Map files can contain POINT directives too, but those are -skipped. This way the same file(s) can be used for both POI and map data. By -default the map coordinates are translated so that the upper left corner of -the map is at coordinate point (0,0). Y-coordinates are mirrored before -translation so that the map's north points up in the playfield view. Also all -POI and route files are translated to match to the map data transformation. - - -Report settings: ---- - -Report.nrofReports -How many report modules to load. Module names are defined with settings -"Report.report1", "Report.report2", etc. Following report settings can be -defined for all reports (using Report name space) or just for certain reports -(using ReportN name spaces). - -Report.reportDir -Where to store the report output files. Can be absolute path or relative to -the path where the simulation was started. If the directory doesn't exists, -it is created. - -Report.warmup -Length of the warm up period (simulated seconds from the start). During the -warm up the report modules should discard the new events. The behavior is -report module specific so check the (java)documentation of different report -modules for details. - - -Event generator settings: ---- - -Events.nrof -How many event generators are loaded for the simulation. Event generator -specific settings (see below) are defined in EventsN namespaces (so -Events1.settingName configures a setting for the 1st event generator etc.). - -EventsN.class -Name of the generator class to load (e.g., ExternalEventsQueue or -MessageEventGenerator). The class must be found from the input package. - -For the ExternalEventsQueue you must at least define the path to the external -events file (using setting "filePath"). See input.StandardEventsReader class' -javadocs for information about different external events. - - -Other settings: ---- - -Optimization.randomizeUpdateOrder -Should the order in which the nodes' update method is called be randomized. -Call to update causes the nodes to check their connections and also update -their routing module. If set to false, node update order is the same as their -network address order. With randomizing, the order is different on every time -step. - -Optimization.cellSizeMult -Adjust the trade-off between memory consumption and simulation speed. -Especially useful for large maps. See ConnectivityOptimizer class for details. - - -GUI -=== - -The GUI's main window is divided into three parts. The main part contains -the playfield view (where node movement is displayed) and simulation and -GUI control and information. The right part is used to select nodes and -the lower part is for logging and breakpoints. - -The main part's topmost section is for simulation and GUI controls. The -first field shows the current simulation time. Next field shows the -simulation speed (simulated seconds per second). The following four -buttons are used to pause, step, fast forward, and fast forward simulation -to given time. Pressing step-button multiple times runs simulation -step-by-step. Fast forward (FFW) can be used to skip uninteresting parts -of simulation. In FFW, the GUI update speed is set to a large value. Next -drop-down is used to control GUI update speed. Speed 1 means that GUI is -updated on every simulated second. Speed 10 means that GUI is updated only -on every 10th second etc. Negative values slow down the simulation. The -following drop-down controls the zoom factor. The last button saves the -current view as a png-image. - -Middle section, i.e., the playfield view, shows the node placement, map -paths, node identifiers, connections among nodes etc. All nodes are -displayed as small rectangles and their radio range is shown as a green -circle around the node. Node's group identifier and network address (a -number) are shown next to each node. If a node is carrying messages, each -message is represented by a green or blue filled rectangle. If node -carries more than 10 messages, another column of rectangles is drawn for -each 10 messages but every other rectangle is now red. You can center the -view to any place by clicking with mouse button on the play field. Zoom -factor can also be changed using mouse wheel on top of the playfield view. - -The right part of main window is for choosing a node for closer inspection. -Simply clicking a button shows the node info in main parts lower section. -From there more information can be displayed by selecting one of the -messages the node is carrying (if any) from the drop-down menu. Pressing -the "routing info" button opens a new window where information about the -routing module is displayed. When a node is chosen, the playfield view is -also centered on that node and the current path the node is traveling is -shown in red. - -Logging (the lowest part) if divided to two sections, control and log. From -the control part you can select what kind of messages are shown in the -log. You can also define if simulation should be paused on certain type of -event (using the check boxes in the "pause" column). Log part displays time -stamped events. All nodes and message names in the log messages are -buttons and you can get more information about them by clicking the -buttons. - - -DTN2 Reference Implementation Connectivity -========================================== - -DTN2 connectivity allows bundles to be passed between the ONE and any -number of DTN2 routers. This is done through DTN2's External Convergence -Layer Interface. - -When DTN2 connectivity is enabled ONE will connect to dtnd routers as -an external convergence layer adapter. ONE will also automatically configure -dtnd through a console connection with a link and route for bundles to reach -the simulator. - -When a bundle is received from dtnd, ONE attempts to match the destination EID -against the regular expressions configured in the configuration file (see DTN2 -Connectivity Configuration File below). For each matching node a copy of a -message is created and routed inside ONE. When the bundle reaches its destination -inside ONE it is delivered to the dtnd router instance attached to the node. -Copies of the bundle payload are stored within 'bundles' directory. - -To enable this functionality the following steps must be taken: - -1) DTN2 must be compiled and configured with ECL support enabled. -2) DTN2Events event generator must be configured to be loaded into ONE - as an events class. -3) DTN2Reporter must be configured and loaded into one as a report class. -4) DTN2 connectivity configuration file must be configured as DTN2.configFile - -To start the simulation: -1) Start all the dtnd router instances. -2) Start ONE. - -Example Configuration (2-4 above) ---------------------------------- - -Events.nrof = 1 -Events1.class = DTN2Events -Report.nrofReports = 1 -Report.report1 = DTN2Reporter -DTN2.configFile = cla.conf - -DTN2 Connectivity Configuration File ------------------------------------- - -The DTN2 connectivity configuration file defines which nodes inside ONE -should connect to which DTN2 router instances. It also defines the EID's -that the nodes match. - -The configuration file is composed of comment lines starting with # and -configuration lines with the following format: - - - -The fields have the following meaning: - -nodeID: The ID of a node inside ONE (integer >= 0) -EID regexp: Incoming bundles whose destination EID matches this regexp - will be forwarded to the node inside ONE. - (see java.util.regex.Pattern) -dtnd host: Hostname/IP of the dtnd router to connect to this node. -ECL port: dtnd router's port listening to ECLAs -console port: dtnd router's console port - -Example: -# -1 dtn://local-1.dtn/(.*) localhost 8801 5051 -2 dtn://local-2.dtn/(.*) localhost 8802 5052 - -Known Issues ------------- - -For DTN2 connectivity related issues, you can contact teemuk@netlab.tkk.fi - --Quitting dtnd router instances connected to ONE will cause ONE to quit. - - -Toolkit -======= - -The simulation package includes a folder called "toolkit" that contains -scripts for generating input and processing the output of the simulator. All -(currently included) scripts are written with Perl (http://www.perl.com/) so -you need to have it installed before running the scripts. Some post processing -scripts use gnuplot (http://www.gnuplot.info/) for creating graphics. Both of -the programs are freely available for most of the Unix/Linux and Windows -environments. For Windows environment, you may need to change the path to the -executables for some of the scripts. - -getStats.pl -This script can be used to create bar-plots of various statistics gathered by -the MessageStatsReport -report module. The only mandatory option is "-stat" -which is used to define the name of the statistics value that should be parsed -from the report files (e.g., "delivery_prob" for message delivery -probabilities). Rest of the parameters should be MessageStatsReport output -filenames (or paths). Script creates three output files: one with values from -all the files, one with the gnuplot commands used to create the graphics and -finally an image file containing the graphics. One bar is created to the plot -for each input file. The title for each bar is parsed from the report filename -using the regular expression defined with "-label" option. Run getStats.pl -with "-help" option for more help. - -ccdfPlotter.pl -Script for creating Complementary(/Inverse) Cumulative Distribution Function -plots (using gluplot) from reports that contain time-hitcount-tuples. Output -filename must be defined with the "-out" option and rest of the parameters -should be (suitable) report filenames. "-label" option can be used for -defining label extracting regular expression (similar to one for the getStats -script) for the legend. - -createCreates.pl -Message creation pattern for the simulation can be defined with external events -file. Such a file can be simply created with any text editor but this script -makes it easier to create a large amount of messages. Mandatory options are -the number of messages ("-nrof"), time range ("-time"), host address range -("-hosts") and message size range ("-sizes"). The number of messages is simply -an integer but the ranges are given with two integers with a colon (:) between -them. If hosts should reply to the messages that they receive, size range of -the reply messages can be defined with "-rsizes" option. If a certain random -number generator seed should be used, that can be defined with "-seed" option. -All random values are drawn from a uniform distribution with inclusive minimum -value and exclusive maximum value. Script outputs commands that are suitable -for external events file's contents. You probably want to redirect the output -to some file. - -dtnsim2parser.pl and transimsParser.pl -These two (quite experimental) parsers convert data from other programs to a -form that is suitable for ONE. Both take two parameters: input and output -file. If these parameters are omitted, stdin and stdout are used for input and -output. With "-h" option a short help is printed. -dtnsim2parser converts dtnsim2's (http://watwire.uwaterloo.ca/DTN/sim/) output -(with verbose mode 8) to an external events file that can be fed to ONE. The -main idea of this parser is that you can first create a connectivity pattern -file using ONE and ConnectivityDtnsim2Report, feed that to dtnsim2 and then -observe the results visually in ONE (using the output converted with -dtnsim2parser as the external events file). -transimsParser can convert TRANSIM's (http://transims-opensource.net/) vehicle -snapshot files to external movement files that can be used as an input for -node movement. See ExternalMovement and ExternalMovementReader classes for -more information. \ No newline at end of file +The ONE v1.6.0 - Readme +======================= + +The ONE is a Opportunistic Network Environment simulator which provides a +powerful tool for generating mobility traces, running DTN messaging +simulations with different routing protocols, and visualizing both +simulations interactively in real-time and results after their completion. + + +Quick start +=========== + +Compiling +--------- + +You can compile ONE from the source code using the included compile.bat +script. That should work both in Windows and Unix/Linux environment with +Java 6 JDK or later. + +If you want to use Eclipse for compiling the ONE, since version 1.1.0 you need +to include some jar libraries in the project's build path. The libraries are +located in the lib folder. To include them in Eclipse, assuming that you have +an Eclipse Java project whose root folder is the folder where you extracted +the ONE, do the following: + +select from menus: Project -> Properties -> Java Build Path +Go to "Libraries" tab +Click "Add JARs..." +Select "DTNConsoleConnection.jar" under the "lib" folder +Add the "ECLA.jar" the same way +Press "OK". + +Now Eclipse should be able to compile the ONE without warnings. + + +Running +------- + +ONE can be started using the included one.bat (for Windows) or one.sh (for +Linux/Unix) script. Following examples assume you're using the Linux/Unix +script (just replace "./one.sh" with "one.bat" for Windows). + +Synopsis: +./one.sh [-b runcount] [conf-files] + +Options: + -b Run simulation in batch mode. Doesn't start GUI but prints +information about the progress to terminal. The option must be followed +by the number of runs to perform in the batch mode or by a range of runs +to perform, delimited with a colon (e.g, value 2:4 would perform runs 2, +3 and 4). See section "Run indexing" for more information. + +Parameters: + conf-files: The configuration file names where simulation parameters +are read from. Any number of configuration files can be defined and they are +read in the order given in the command line. Values in the later config files +override values in earlier config files. + + +Configuring +=========== + +All simulation parameters are given using configuration files. These files +are normal text files that contain key-value pairs. Syntax for most of the +variables is: +Namespace.key = value + +I.e., the key is (usually) prefixed by a namespace, followed by a dot, and +then key name. Key and value are separated by equals-sign. Namespaces +start with capital letter and both namespace and keys are written in +CamelCase (and are case sensitive). Namespace defines (loosely) the part +of the simulation environment where the setting has effect on. Many, but +not all, namespaces are equal to the class name where they are read. +Especially movement models, report modules and routing modules follow this +convention. In some cases the namespace is defined by the user: e.g., with +network interfaces user can pick up any idenfitier, define interface specific +settings in that namespace, and give the name of the namespace when +configuring which interface each group should use. + +Numeric values use '.' as the decimal separator and can be suffixed with +kilo (k) mega (M) or giga (G) suffix. Boolean settings accept "true", +"false", "0", and "1" as values. + +Many settings define paths to external data files. The paths can be relative +or absolute but the directory separator must be '/' in both Unix and Windows +environment. + +Some variables contain comma-separated values, and for them the syntax is: +Namespace.key = value1, value2, value3, etc. + +For run-indexed values the syntax is: +Namespace.key = [run1value; run2value; run3value; etc] +I.e., all values are given in brackets and values for different run are +separated by semicolon. Each value can also be a comma-separated value. +For more information about run indexing, go to section "Run indexing". + +Setting files can contain comments too. A comment line must start with "#" +character. Rest of the line is skipped when the settings are read. This can +be also useful for disabling settings easily. + +Some values (scenario and report names at the moment) support "value +filling". With this feature, you can construct e.g., scenario name +dynamically from the setting values. This is especially useful when using +run indexing. Just put setting key names in the value part prefixed and +suffixed by two percent (%) signs. These placeholders are replaces by the +current setting value from the configuration file. See the included +snw_comparison_settings.txt for an example. + +File "default_settings.txt", if exists, is always read and the other +configuration files given as parameter can define more settings or override +some (or even all) settings in the previous files. The idea is that +you can define in the earlier files all the settings that are common for +all the simulations and run different, specific, simulations using +different configuration files. + + +Run indexing +------------ + +Run indexing is a feature that allows you to run large amounts of +different configurations using only single configuration file. The idea is +that you provide an array of settings (using the syntax described above) +for the variables that should be changed between runs. For example, if you +want to run the simulation using five different random number generator +seeds for movement models, you can define in the settings file the +following: + +MovementModel.rngSeed = [1; 2; 3; 4; 5] + +Now, if you run the simulation using command: + +./one.sh -b 5 my_config.txt + +you would run first using seed 1 (run index 0), then another run using +seed 2, etc. Note that you have to run it using batch mode (-b option) if +you want to use different values. Without the batch mode flag the first +parameter (if numeric) is the run index to use when running in GUI mode. + +Run indexes wrap around: used value is the value at index (runIndex % +arrayLength). Because of wrapping, you can easily run large amount of +permutations easily. For example, if you define two key-value pairs: + +key1 = [1; 2] +key2 = [a; b; c] + +and run simulation using run-index count 6, you would get all permutations +of the two values (1,a; 2,b; 1,c; 2,a; 1,b; 2,c). This naturally works +with any amount of arrays. Just make sure that the smallest common +nominator of all array sizes is 1 (e.g., use arrays whose sizes are primes) +-- unless you don't want all permutations but some values should be +paired. + + +Movement models +--------------- + +Movement models govern the way nodes move in the simulation. They provide +coordinates, speeds and pause times for the nodes. The basic installation +contains, e.g., random waypoint, map based movement, shortest path map based +movement, map route movement, and external movement. All these models, except +external movement, have configurable speed and pause time distributions. A +minimum and maximum values can be given and the movement model draws +uniformly distributed random values that are within the given range. Same +applies for pause times. In external movement model the speeds and pause +times are interpreted from the given data. + +When a node uses the random waypoint movement model (RandomWaypoint), it is +given a random coordinate in the simulation area. Node moves directly to the +given destination at constant speed, pauses for a while, and then gets a new +destination. This continues throughout the simulations and nodes move along +these zig-zag paths. + +Map-based movement models constrain the node movement to predefined paths. +Different types of paths can be defined and one can define valid paths for +all node groups. This way e.g., cars can be prevented from driving indoors or +on pedestrian paths. + +The basic map-based movement model (MapBasedMovement) initially distributes +the nodes between any two adjacent (i.e., connected by a path) map nodes and +then nodes start moving from adjacent map node to another. When node reaches +the next map node, it randomly selects the next adjacent map node but chooses +the map node where it came from only if that is the only option (i.e., avoids +going back to where it came from). Once node has moved trough 10-100 map +nodes, it pauses for a while and then starts moving again. + +The more sophisticated version of the map-based movement model +(ShortestPathMapBasedMovement) uses Dijkstra's shortest path algorithm to +find its way trough the map area. Once a node reaches its destination, and +has waited for the pause time, a new random map node is chosen and node moves +there using the shortest path that can be taken using only valid map nodes. + +For the shortest path based movement models, map data can also contain Points +Of Interest (POIs). Instead of selecting any random map node for the next +destination, the movement model can be configured to give a POI belonging to +a certain POI group with a configurable probability. There can be unlimited +amount of POI groups and all groups can contain any amount of POIs. All node +groups can have different probabilities for all POI groups. POIs can be used +to model e.g., shops, restaurants and tourist attractions. + +Route based movement model (MapRouteMovement) can be used to model nodes that +follow certain routes, e.g. bus or tram lines. Only the stops on the route +have to be defined and then the nodes using that route move from stop to stop +using shortest paths and stop on the stops for the configured time. + +All movement models can also decide when the node is active (moves and can be +connected to) and when not. For all models, except for the external movement, +multiple simulation time intervals can be given and the nodes in that group +will be active only during those times. + +All map-based models get their input data using files formatted with a subset +of the Well Known Text (WKT) format. LINESTRING and MULTILINESTRING +directives of WKT files are supported by the parser for map path data. For +point data (e.g. for POIs), also the POINT directive is supported. Adjacent +nodes in a (MULTI)LINESTRING are considered to form a path and if some lines +contain some vertex(es) with exactly the same coordinates, the paths are +joined from those places (this is how you create intersections). WKT files +can be edited and generated from real world map data using any suitable +Geographic Information System (GIS) program. The map data included in the +simulator distribution was converted and edited using the free, Java based +OpenJUMP GIS program. + +Different map types are defined by storing the paths belonging to different +types to different files. Points Of Interest are simply defined with WKT +POINT directive and POI groups are defined by storing all POIs belonging to a +certain group in the same file. All POIs must also be part of the map data so +they are accessible using the paths. Stops for the routes are defined with +LINESTRING and the stops are traversed in the same order they appear in the +LINESTRING. One WKT file can contain multiple routes and they are given to +nodes in the same order as they appear in the file. + +The experimental movement model that uses external movement data +(ExternalMovement) reads timestamped node locations from a file and moves the +nodes in the simulation accordingly. See javadocs of ExternalMovementReader +class from input package for details of the format. A suitable, experimental +converter script (transimsParser.pl) for TRANSIMS data is included in the +toolkit folder. + +The movement model to use is defined per node group with the "movementModel" +setting. Value of the setting must be a valid movement model class name from +the movement package. Settings that are common for all movement models are +read in the MovementModel class and movement model specific settings are read +in the respective classes. See the javadoc documentation and example +configuration files for details. + +Routing modules and message creation +------------------------------------ + +Routing modules define how the messages are handled in the simulation. Six +basic active routing modules (First Contact, Epidemic, Spray and Wait, Direct +delivery, PRoPHET and MaxProp) and also a passive router for external routing +simulation are included in the package. The active routing modules are +implementations of the well known routing algorithms for DTN routing. There +are also variants of these models and couple of different models included in +the latest versions. See the classes in the routing package for details. + +Passive router is made especially for interacting with other (DTN) routing +simulators or running simulations that don't need any routing functionality. +The router doesn't do anything unless commanded by external events. These +external events are provided to the simulator by a class that implements the +EventQueue interface. + +There are two basic classes that can be used as a source of message events: +ExternalEventsQueue and MessageEventGenerator. The former can read events +from a file that can be created by hand, with a suitable script (e.g., +createCreates.pl script in the toolkit folder), or by converting e.g., +dtnsim2's output to suitable form. See StandardEventsReader class from input +package for details of the format. MessageEventGenerator is a simple message +generator class that creates uniformly distributed message creation patterns +with configurable message creation interval, message size and +source/destination host ranges. More specific messaging scenarios can be +created with MessageBurstGenerator, and One{From,To}EachMessageGenerator +classes. See javadocs for details. + +The toolkit folder contains an experimental parser script (dtnsim2parser.pl) +for dtnsim2's output (there used to be a more capable Java-based parser but +it was discarded in favor of this more easily extendable script). The script +requires a few patches to dtnsim2's code and those can be found from the +toolkit/dtnsim2patches folder. + +The routing module to use is defined per node group with the setting +"router". All routers can't interact properly (e.g., PRoPHET router can only +work with other PRoPHET routers) so usually it makes sense to use the same +(or compatible) router for all groups. + +Reports +------- + +Reports can be used to create summary data of simulation runs, detailed data +of connections and messages, files suitable for post-processing using e.g., +Graphviz (to create graphs) and also to interface with other programs. See +javadocs of report-package classes for details. + +There can be any number of reports for any simulation run and the number of +reports to load is defined with "Report.nrofReports" setting. Report class +names are defined with "Report.reportN" setting, where N is an integer value +starting from 1. The values of the settings must be valid report class names +from the report package. The output directory of all reports (which can be +overridden per report class with the "output" setting) must be defined with +Report.reportDir -setting. If no "output" setting is given for a report +class, the resulting report file name is "ReportClassName_ScenarioName.txt". + +All reports have many configurable settings which can be defined using +ReportClassName.settingKey -syntax. See javadocs of Report class and specific +report classes for details (look for "setting id" definitions). + +Host groups +----------- + +A host group is group of hosts (nodes) that shares movement and routing +module settings. Different groups can have different values for the settings +and this way they can represent different types of nodes. Base settings can +be defined in the "Group" namespace and different node groups can override +these settings or define new settings in their specific namespaces (Group1, +Group2, etc.). + +The settings +------------ + +There are plenty of settings to configure; more than is meaningful to +present here. See javadocs of especially report, routing and movement +model classes for details. See also included settings files for examples. +Perhaps the most important settings are the following. + + +Scenario settings: +--- + +Scenario.name +Name of the scenario. All report files are by default prefixed with this. + +Scenario.simulateConnections +Should connections be simulated. If you're only interested in movement +modeling, you can disable this to get faster simulation. Usually you want +this to be on. + +Scenario.updateInterval +How many seconds are stepped on every update. Increase this to get faster +simulation, but then you'll lose some precision. Values from 0.1 to 2 are good +for simulations. + +Scenario.endTime +How many simulated seconds to simulate. + +Scenario.nrofHostGroups +How many hosts group are present in the simulation. + + +Interface settings (used to define the possible interfaces the nodes can have) +--- + +type +What class (from the interfaces-directory) is used for this interface + +The remaining settings are class-specific. Can be for example: + +transmitRange +Range (meters) of the interface. + +transmitSpeed +Transmit speed of the interface (bytes per second). + + +Host group settings (used in Group or GroupN namespace): +--- + +groupID +Group's identifier (a string or a character). Used as the prefix of host +names that are shown in the GUI and reports. Host's full name is +groupID+networkAddress. + +nrofHosts +Number of hosts in this group. + +nrofInterfaces +Number of interfaces this the nodes of this group use + +interfaceX +The interface that should be used as the interface number X + +movementModel +The movement model all hosts in the group use. Must be a valid class (one +that is a subclass of MovementModel class) name from the movement package. + +waitTime +Minimum and maximum (two comma-separated decimal values) of the wait time +interval (seconds). Defines how long nodes should stay in the same place +after reaching the destination of the current path. A new random value within +the interval is used on every stop. Default value is 0,0. + +speed +Minimum and maximum (two comma-separated decimal values) of the speed +interval (m/s). Defines how fast nodes move. A new random value is used on +every new path. Default value is 1,1. + +bufferSize +Size of the nodes' message buffer (bytes). When the buffer is full, node can't +accept any more messages unless it drops some old messages from the buffer. + +router +Router module which is used to route messages. Must be a valid class +(subclass of MessageRouter class) name from routing package. + +activeTimes +Time intervals (comma-separated simulated time value tuples: start1, end1, +start2, end2, ...) when the nodes in the group should be active. If no +intervals are defined, nodes are active all the time. + +msgTtl +Time To Live (simulated minutes) of the messages created by this host group. +Nodes (with active routing module) check every one minute whether some of +their messages' TTLs have expired and drop such messages. If no TTL is +defined, infinite TTL is used. + + +Group and movement model specific settings (only meaningful for certain +movement models): + +pois +Points Of Interest indexes and probabilities (comma-separated +index-probability tuples: poiIndex1, poiProb1, poiIndex2, poiProb2, ... ). +Indexes are integers and probabilities are decimal values in the range of +0.0-1.0. Setting defines the POI groups where the nodes in this host group +can choose destinations from and the probabilities for choosing a certain POI +group. For example, a (random) POI from the group defined in the POI file1 +(defined with PointsOfInterest.poiFile1 setting) is chosen with the +probability poiProb1. If the sum of all probabilities is less than 1.0, a +probability of choosing any random map node for the next destination is (1.0 +- theSumOfProbabilities). Setting can be used only with +ShortestPathMapBasedMovement -based movement models. + +okMaps +Which map node types (refers to map file indexes) are OK for the group +(comma-separated list of integers). Nodes will not travel trough map nodes +that are not OK for them. As default, all map nodes are OK. Setting can be +used with any MapBasedMovent -based movement model. + +routeFile +If MapRouteMovement movement model is used, this setting defines the route +file (path) where the route is read from. Route file should contain +LINESTRING WKT directives. Each vertex in a LINESTRING represents one stop +on the route. + +routeType +If MapRouteMovement movement model is used, this setting defines the routes +type. Type can be either circular (value 1) or ping-pong (value 2). See +movement.map.MapRoute class for details. + + +Movement model settings: +--- + +MovementModel.rngSeed +The seed for all movement models' random number generator. If the seed and +all the movement model related settings are kept the same, all nodes should +move the same way in different simulations (same destinations and speed & +wait time values are used). + +MovementModel.worldSize +Size of the simulation world in meters (two comma separated values: +width, height). + +PointsOfInterest.poiFileN +For ShortestPathMapBasedMovement -based movement models, this setting defines +the WKT files where the POI coordinates are read from. POI coordinates are +defined using the POINT WKT directive. The "N" in the end of the setting must +be a positive integer (i.e., poiFile1, poiFile2, ...). + +MapBasedMovement.nrofMapFiles +How many map file settings to look for in the settings file. + +MapBasedMovement.mapFileN +Path to the Nth map file ("N" must be a positive integer). There must be at +least nrofMapFiles separate files defined in the configuration files(s). All +map files must be WKT files with LINESTRING and/or MULTILINESTRING WKT +directives. Map files can contain POINT directives too, but those are +skipped. This way the same file(s) can be used for both POI and map data. By +default the map coordinates are translated so that the upper left corner of +the map is at coordinate point (0,0). Y-coordinates are mirrored before +translation so that the map's north points up in the playfield view. Also all +POI and route files are translated to match to the map data transformation. + + +Report settings: +--- + +Report.nrofReports +How many report modules to load. Module names are defined with settings +"Report.report1", "Report.report2", etc. Following report settings can be +defined for all reports (using Report name space) or just for certain reports +(using ReportN name spaces). + +Report.reportDir +Where to store the report output files. Can be absolute path or relative to +the path where the simulation was started. If the directory doesn't exists, +it is created. + +Report.warmup +Length of the warm up period (simulated seconds from the start). During the +warm up the report modules should discard the new events. The behavior is +report module specific so check the (java)documentation of different report +modules for details. + + +Event generator settings: +--- + +Events.nrof +How many event generators are loaded for the simulation. Event generator +specific settings (see below) are defined in EventsN namespaces (so +Events1.settingName configures a setting for the 1st event generator etc.). + +EventsN.class +Name of the generator class to load (e.g., ExternalEventsQueue or +MessageEventGenerator). The class must be found from the input package. + +For the ExternalEventsQueue you must at least define the path to the external +events file (using setting "filePath"). See input.StandardEventsReader class' +javadocs for information about different external events. + + +Other settings: +--- + +Optimization.randomizeUpdateOrder +Should the order in which the nodes' update method is called be randomized. +Call to update causes the nodes to check their connections and also update +their routing module. If set to false, node update order is the same as their +network address order. With randomizing, the order is different on every time +step. + +Optimization.cellSizeMult +Adjust the trade-off between memory consumption and simulation speed. +Especially useful for large maps. See ConnectivityOptimizer class for details. + + +GUI +=== + +The GUI's main window is divided into three parts. The main part contains +the playfield view (where node movement is displayed) and simulation and +GUI control and information. The right part is used to select nodes and +the lower part is for logging and breakpoints. + +The main part's topmost section is for simulation and GUI controls. The +first field shows the current simulation time. Next field shows the +simulation speed (simulated seconds per second). The following four +buttons are used to pause, step, fast forward, and fast forward simulation +to given time. Pressing step-button multiple times runs simulation +step-by-step. Fast forward (FFW) can be used to skip uninteresting parts +of simulation. In FFW, the GUI update speed is set to a large value. Next +drop-down is used to control GUI update speed. Speed 1 means that GUI is +updated on every simulated second. Speed 10 means that GUI is updated only +on every 10th second etc. Negative values slow down the simulation. The +following drop-down controls the zoom factor. The last button saves the +current view as a png-image. + +Middle section, i.e., the playfield view, shows the node placement, map +paths, node identifiers, connections among nodes etc. All nodes are +displayed as small rectangles and their radio range is shown as a green +circle around the node. Node's group identifier and network address (a +number) are shown next to each node. If a node is carrying messages, each +message is represented by a green or blue filled rectangle. If node +carries more than 10 messages, another column of rectangles is drawn for +each 10 messages but every other rectangle is now red. You can center the +view to any place by clicking with mouse button on the play field. Zoom +factor can also be changed using mouse wheel on top of the playfield view. + +The right part of main window is for choosing a node for closer inspection. +Simply clicking a button shows the node info in main parts lower section. +From there more information can be displayed by selecting one of the +messages the node is carrying (if any) from the drop-down menu. Pressing +the "routing info" button opens a new window where information about the +routing module is displayed. When a node is chosen, the playfield view is +also centered on that node and the current path the node is traveling is +shown in red. + +Logging (the lowest part) if divided to two sections, control and log. From +the control part you can select what kind of messages are shown in the +log. You can also define if simulation should be paused on certain type of +event (using the check boxes in the "pause" column). Log part displays time +stamped events. All nodes and message names in the log messages are +buttons and you can get more information about them by clicking the +buttons. + + +DTN2 Reference Implementation Connectivity +========================================== + +DTN2 connectivity allows bundles to be passed between the ONE and any +number of DTN2 routers. This is done through DTN2's External Convergence +Layer Interface. + +When DTN2 connectivity is enabled ONE will connect to dtnd routers as +an external convergence layer adapter. ONE will also automatically configure +dtnd through a console connection with a link and route for bundles to reach +the simulator. + +When a bundle is received from dtnd, ONE attempts to match the destination EID +against the regular expressions configured in the configuration file (see DTN2 +Connectivity Configuration File below). For each matching node a copy of a +message is created and routed inside ONE. When the bundle reaches its destination +inside ONE it is delivered to the dtnd router instance attached to the node. +Copies of the bundle payload are stored within 'bundles' directory. + +To enable this functionality the following steps must be taken: + +1) DTN2 must be compiled and configured with ECL support enabled. +2) DTN2Events event generator must be configured to be loaded into ONE + as an events class. +3) DTN2Reporter must be configured and loaded into one as a report class. +4) DTN2 connectivity configuration file must be configured as DTN2.configFile + +To start the simulation: +1) Start all the dtnd router instances. +2) Start ONE. + +Example Configuration (2-4 above) +--------------------------------- + +Events.nrof = 1 +Events1.class = DTN2Events +Report.nrofReports = 1 +Report.report1 = DTN2Reporter +DTN2.configFile = cla.conf + +DTN2 Connectivity Configuration File +------------------------------------ + +The DTN2 connectivity configuration file defines which nodes inside ONE +should connect to which DTN2 router instances. It also defines the EID's +that the nodes match. + +The configuration file is composed of comment lines starting with # and +configuration lines with the following format: + + + +The fields have the following meaning: + +nodeID: The ID of a node inside ONE (integer >= 0) +EID regexp: Incoming bundles whose destination EID matches this regexp + will be forwarded to the node inside ONE. + (see java.util.regex.Pattern) +dtnd host: Hostname/IP of the dtnd router to connect to this node. +ECL port: dtnd router's port listening to ECLAs +console port: dtnd router's console port + +Example: +# +1 dtn://local-1.dtn/(.*) localhost 8801 5051 +2 dtn://local-2.dtn/(.*) localhost 8802 5052 + +Known Issues +------------ + +For DTN2 connectivity related issues, you can contact teemuk@netlab.tkk.fi + +-Quitting dtnd router instances connected to ONE will cause ONE to quit. + + +Toolkit +======= + +The simulation package includes a folder called "toolkit" that contains +scripts for generating input and processing the output of the simulator. All +(currently included) scripts are written with Perl (http://www.perl.com/) so +you need to have it installed before running the scripts. Some post processing +scripts use gnuplot (http://www.gnuplot.info/) for creating graphics. Both of +the programs are freely available for most of the Unix/Linux and Windows +environments. For Windows environment, you may need to change the path to the +executables for some of the scripts. + +getStats.pl +This script can be used to create bar-plots of various statistics gathered by +the MessageStatsReport -report module. The only mandatory option is "-stat" +which is used to define the name of the statistics value that should be parsed +from the report files (e.g., "delivery_prob" for message delivery +probabilities). Rest of the parameters should be MessageStatsReport output +filenames (or paths). Script creates three output files: one with values from +all the files, one with the gnuplot commands used to create the graphics and +finally an image file containing the graphics. One bar is created to the plot +for each input file. The title for each bar is parsed from the report filename +using the regular expression defined with "-label" option. Run getStats.pl +with "-help" option for more help. + +ccdfPlotter.pl +Script for creating Complementary(/Inverse) Cumulative Distribution Function +plots (using gluplot) from reports that contain time-hitcount-tuples. Output +filename must be defined with the "-out" option and rest of the parameters +should be (suitable) report filenames. "-label" option can be used for +defining label extracting regular expression (similar to one for the getStats +script) for the legend. + +createCreates.pl +Message creation pattern for the simulation can be defined with external events +file. Such a file can be simply created with any text editor but this script +makes it easier to create a large amount of messages. Mandatory options are +the number of messages ("-nrof"), time range ("-time"), host address range +("-hosts") and message size range ("-sizes"). The number of messages is simply +an integer but the ranges are given with two integers with a colon (:) between +them. If hosts should reply to the messages that they receive, size range of +the reply messages can be defined with "-rsizes" option. If a certain random +number generator seed should be used, that can be defined with "-seed" option. +All random values are drawn from a uniform distribution with inclusive minimum +value and exclusive maximum value. Script outputs commands that are suitable +for external events file's contents. You probably want to redirect the output +to some file. + +dtnsim2parser.pl and transimsParser.pl +These two (quite experimental) parsers convert data from other programs to a +form that is suitable for ONE. Both take two parameters: input and output +file. If these parameters are omitted, stdin and stdout are used for input and +output. With "-h" option a short help is printed. +dtnsim2parser converts dtnsim2's (http://watwire.uwaterloo.ca/DTN/sim/) output +(with verbose mode 8) to an external events file that can be fed to ONE. The +main idea of this parser is that you can first create a connectivity pattern +file using ONE and ConnectivityDtnsim2Report, feed that to dtnsim2 and then +observe the results visually in ONE (using the output converted with +dtnsim2parser as the external events file). +transimsParser can convert TRANSIM's (http://transims-opensource.net/) vehicle +snapshot files to external movement files that can be used as an input for +node movement. See ExternalMovement and ExternalMovementReader classes for +more information. diff --git a/applications/PingApplication.java b/applications/PingApplication.java index b2787db20..9e175b813 100644 --- a/applications/PingApplication.java +++ b/applications/PingApplication.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package applications; @@ -17,14 +17,14 @@ import core.World; /** - * Simple ping application to demonstrate the application support. The + * Simple ping application to demonstrate the application support. The * application can be configured to send pings with a fixed interval or to only * answer to pings it receives. When the application receives a ping it sends * a pong message in response. - * + * * The corresponding PingAppReporter class can be used to record * information about the application behavior. - * + * * @see PingAppReporter * @author teemuk */ @@ -43,10 +43,10 @@ public class PingApplication extends Application { public static final String PING_PING_SIZE = "pingSize"; /** Size of the pong message */ public static final String PING_PONG_SIZE = "pongSize"; - + /** Application ID */ public static final String APP_ID = "fi.tkk.netlab.PingApplication"; - + // Private vars private double lastPing = 0; private double interval = 500; @@ -57,10 +57,10 @@ public class PingApplication extends Application { private int pingSize=1; private int pongSize=1; private Random rng; - - /** + + /** * Creates a new ping application with the given settings. - * + * * @param s Settings to use for initializing the application. */ public PingApplication(Settings s) { @@ -87,14 +87,14 @@ public PingApplication(Settings s) { this.destMin = destination[0]; this.destMax = destination[1]; } - + rng = new Random(this.seed); super.setAppID(APP_ID); } - - /** + + /** * Copy-constructor - * + * * @param a */ public PingApplication(PingApplication a) { @@ -109,11 +109,11 @@ public PingApplication(PingApplication a) { this.pingSize = a.getPingSize(); this.rng = new Random(this.seed); } - - /** + + /** * Handles an incoming message. If the message is a ping message replies * with a pong message. Generates events for ping and pong messages. - * + * * @param msg message received by the router * @param host host to which the application instance is attached */ @@ -121,33 +121,33 @@ public PingApplication(PingApplication a) { public Message handle(Message msg, DTNHost host) { String type = (String)msg.getProperty("type"); if (type==null) return msg; // Not a ping/pong message - + // Respond with pong if we're the recipient if (msg.getTo()==host && type.equalsIgnoreCase("ping")) { - String id = "pong" + SimClock.getIntTime() + "-" + + String id = "pong" + SimClock.getIntTime() + "-" + host.getAddress(); Message m = new Message(host, msg.getFrom(), id, getPongSize()); m.addProperty("type", "pong"); m.setAppID(APP_ID); host.createNewMessage(m); - + // Send event to listeners super.sendEventToListeners("GotPing", null, host); super.sendEventToListeners("SentPong", null, host); } - + // Received a pong reply if (msg.getTo()==host && type.equalsIgnoreCase("pong")) { // Send event to listeners super.sendEventToListeners("GotPong", null, host); } - + return msg; } - /** + /** * Draws a random host from the destination range - * + * * @return host */ private DTNHost randomHost() { @@ -159,15 +159,15 @@ private DTNHost randomHost() { World w = SimScenario.getInstance().getWorld(); return w.getNodeByAddress(destaddr); } - + @Override public Application replicate() { return new PingApplication(this); } - /** + /** * Sends a ping packet if this is an active application instance. - * + * * @param host to which the application instance is attached */ @Override @@ -182,10 +182,10 @@ public void update(DTNHost host) { m.addProperty("type", "ping"); m.setAppID(APP_ID); host.createNewMessage(m); - + // Call listeners super.sendEventToListeners("SentPing", null, host); - + this.lastPing = curTime; } } diff --git a/core/Application.java b/core/Application.java index d2aabaeec..98520c725 100644 --- a/core/Application.java +++ b/core/Application.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package core; @@ -14,12 +14,12 @@ * properties of the message before returning it or return null to signal * to the router that it wants the message to be dropped. *

- * + * *

* In addition, the application's update() method is called every * simulation cycle. *

- * + * *

* Configuration of application is done by picking a unique application instance * name (e.g., mySimpleApp) and setting its type property to the @@ -28,37 +28,37 @@ * Group.application setting: Group1.application = * mySimpleApp. *

- * + * * @author mjpitka * @author teemuk */ public abstract class Application { private List aListeners = null; - + public String appID = null; - public Application(){ + public Application(){ } - + /** * Copy constructor. - * + * * @param app */ - public Application(Application app){ + public Application(Application app){ this.aListeners = app.getAppListeners(); this.appID = app.appID; } - + /** - * This method handles application functionality related to - * processing of the bundle. Application handles a messages, - * which arrives to the node hosting this application. After - * performing application specific handling, this method returns - * a list of messages. If node wishes to continue forwarding the + * This method handles application functionality related to + * processing of the bundle. Application handles a messages, + * which arrives to the node hosting this application. After + * performing application specific handling, this method returns + * a list of messages. If node wishes to continue forwarding the * incoming - * + * * @param msg The incoming message. * @param host The host this application instance is attached to. * @return the (possibly modified) message to forward or null @@ -66,52 +66,52 @@ public Application(Application app){ * message. */ public abstract Message handle(Message msg, DTNHost host); - - /** + + /** * Called every simulation cycle. - * + * * @param host The host this application instance is attached to. */ public abstract void update(DTNHost host); - - /** + + /** *

* Returns an unique application ID. The application will only receive * messages with this application ID. If the AppID is set to * null the application will receive all messages. *

- * + * * @return Application ID. */ public String getAppID() { return this.appID; } - - /** + + /** * Sets the application ID. Should only set once when the application is * created. Changing the value during simulation runtime is not recommended * unless you really know what you're doing. - * + * * @param appID */ public void setAppID(String appID) { this.appID = appID; } - + public abstract Application replicate(); - + public void setAppListeners (List aListeners){ this.aListeners = aListeners; } - + public List getAppListeners(){ return this.aListeners; } - - /** + + /** * Sends an event to all listeners. - * + * * @param event The event to send. * @param params Any additional parameters to send. * @param host The host which where the app is running. diff --git a/core/ApplicationListener.java b/core/ApplicationListener.java index 2d22c397c..0dc1155de 100644 --- a/core/ApplicationListener.java +++ b/core/ApplicationListener.java @@ -1,35 +1,35 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - +package core; + /** - *

- * Interface for classes that want to be informed about messages + *

+ * Interface for classes that want to be informed about messages * between hosts. *

- * + * *

* Report classes wishing to receive application events should implement this * interface. Note that the application event names are defined by the * applications so any class wishing to interpret them must know the * application. *

- * + * * @author teemuk - * @author mjpitka - */ -public interface ApplicationListener { - - /** + * @author mjpitka + */ +public interface ApplicationListener { + + /** * Application has generated an event. - * + * * @param event Event name. * @param params Additional parameters for the event * @param app Application instance that generated the event. * @param host The host this application instance is running on. - */ + */ public void gotEvent(String event, Object params, Application app, - DTNHost host); -} + DTNHost host); +} diff --git a/core/ArithmeticCondition.java b/core/ArithmeticCondition.java index 448acf046..20ba948cf 100644 --- a/core/ArithmeticCondition.java +++ b/core/ArithmeticCondition.java @@ -1,83 +1,83 @@ -/* - * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package core; - -/** - * This class presents a simple arithmetic condition: is value smaller than, - * bigger than, or equal to another value. The condition is given in text - * form, e.g., "< 42", and then different values can be matched against that - * condition. - * @author Ari - */ -public class ArithmeticCondition { - - private static final String VALID_OPERATORS = "><="; - private char operator; - private double number; - - /** - * Creates a new condition based on the given string. - * @param cond The condition string. Must consist of one operator - * ("<", ">", or "=") and one double-precision floating point number. - * @throws SettingsError if the given string is not a valid condition - */ - public ArithmeticCondition(String cond) { - String value; - int multiplier = 1; - - if (cond.length() < 2) { - throw new SettingsError("Invalid condition \"" + cond + "\""); - } - - operator = cond.charAt(0); - value = cond.substring(1); - - /* handle kilo and Mega suffixes for the value */ - if (value.endsWith("k")) { - multiplier = 1000; - } else if (value.endsWith("M")) { - multiplier = 1000000; - } - if (multiplier > 1) { /* remove suffix */ - value = value.substring(0, value.length() - 1); - } - - if (VALID_OPERATORS.indexOf(operator) == -1) { - throw new SettingsError("Invalid operator in condition \"" + cond + - "\" valid operators: " + VALID_OPERATORS); - } - - try { - number = Double.parseDouble(value); - } catch (NumberFormatException e) { - throw new SettingsError("Invalid numeric value in condition \"" + - cond + "\""); - } - - number *= multiplier; - - } - - /** - * Returns true if the given value satisfies "V X N" where V is the given - * value, X is the operator (from the settings), and N is the numeric value - * given after the operator in the settings. - * @param value The value to check - * @return true if the condition holds for the given value, false otherwise - */ - public boolean isTrueFor(double value) { - switch (operator) { - case '<': return value < this.number; - case '>': return value > this.number; - case '=': return value == this.number; // XXX: == for doubles... - default: throw new SettingsError("Invalid operator"); - } - } - - @Override - public String toString() { - return "Condition \"" + operator + " " + number + "\""; - } -} +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + * This class presents a simple arithmetic condition: is value smaller than, + * bigger than, or equal to another value. The condition is given in text + * form, e.g., "< 42", and then different values can be matched against that + * condition. + * @author Ari + */ +public class ArithmeticCondition { + + private static final String VALID_OPERATORS = "><="; + private char operator; + private double number; + + /** + * Creates a new condition based on the given string. + * @param cond The condition string. Must consist of one operator + * ("<", ">", or "=") and one double-precision floating point number. + * @throws SettingsError if the given string is not a valid condition + */ + public ArithmeticCondition(String cond) { + String value; + int multiplier = 1; + + if (cond.length() < 2) { + throw new SettingsError("Invalid condition \"" + cond + "\""); + } + + operator = cond.charAt(0); + value = cond.substring(1); + + /* handle kilo and Mega suffixes for the value */ + if (value.endsWith("k")) { + multiplier = 1000; + } else if (value.endsWith("M")) { + multiplier = 1000000; + } + if (multiplier > 1) { /* remove suffix */ + value = value.substring(0, value.length() - 1); + } + + if (VALID_OPERATORS.indexOf(operator) == -1) { + throw new SettingsError("Invalid operator in condition \"" + cond + + "\" valid operators: " + VALID_OPERATORS); + } + + try { + number = Double.parseDouble(value); + } catch (NumberFormatException e) { + throw new SettingsError("Invalid numeric value in condition \"" + + cond + "\""); + } + + number *= multiplier; + + } + + /** + * Returns true if the given value satisfies "V X N" where V is the given + * value, X is the operator (from the settings), and N is the numeric value + * given after the operator in the settings. + * @param value The value to check + * @return true if the condition holds for the given value, false otherwise + */ + public boolean isTrueFor(double value) { + switch (operator) { + case '<': return value < this.number; + case '>': return value > this.number; + case '=': return value == this.number; // XXX: == for doubles... + default: throw new SettingsError("Invalid operator"); + } + } + + @Override + public String toString() { + return "Condition \"" + operator + " " + number + "\""; + } +} diff --git a/core/CBRConnection.java b/core/CBRConnection.java index 0db8634bd..9768aaa8f 100644 --- a/core/CBRConnection.java +++ b/core/CBRConnection.java @@ -1,124 +1,124 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package core; - -import routing.MessageRouter; - -/** - * A constant bit-rate connection between two DTN nodes. - */ -public class CBRConnection extends Connection { - private int speed; - private double transferDoneTime; - - /** - * Creates a new connection between nodes and sets the connection - * state to "up". - * @param fromNode The node that initiated the connection - * @param fromInterface The interface that initiated the connection - * @param toNode The node in the other side of the connection - * @param toInterface The interface in the other side of the connection - * @param connectionSpeed Transfer speed of the connection (Bps) when - * the connection is initiated - */ - public CBRConnection(DTNHost fromNode, NetworkInterface fromInterface, - DTNHost toNode, NetworkInterface toInterface, int connectionSpeed) { - super(fromNode, fromInterface, toNode, toInterface); - this.speed = connectionSpeed; - this.transferDoneTime = 0; - - } - - /** - * Sets a message that this connection is currently transferring. If message - * passing is controlled by external events, this method is not needed - * (but then e.g. {@link #finalizeTransfer()} and - * {@link #isMessageTransferred()} will not work either). Only a one message - * at a time can be transferred using one connection. - * @param from The host sending the message - * @param m The message - * @return The value returned by - * {@link MessageRouter#receiveMessage(Message, DTNHost)} - */ - public int startTransfer(DTNHost from, Message m) { - assert this.msgOnFly == null : "Already transferring " + - this.msgOnFly + " from " + this.msgFromNode + " to " + - this.getOtherNode(this.msgFromNode) + ". Can't " + - "start transfer of " + m + " from " + from; - - this.msgFromNode = from; - Message newMessage = m.replicate(); - int retVal = getOtherNode(from).receiveMessage(newMessage, from); - - if (retVal == MessageRouter.RCV_OK) { - this.msgOnFly = newMessage; - this.transferDoneTime = SimClock.getTime() + - (1.0*m.getSize()) / this.speed; - } - - return retVal; - } - - /** - * Aborts the transfer of the currently transferred message. - */ - public void abortTransfer() { - assert msgOnFly != null : "No message to abort at " + msgFromNode; - getOtherNode(msgFromNode).messageAborted(this.msgOnFly.getId(), - msgFromNode,getRemainingByteCount()); - clearMsgOnFly(); - this.transferDoneTime = 0; - } - - /** - * Gets the transferdonetime - */ - public double getTransferDoneTime() { - return transferDoneTime; - } - - /** - * Returns true if the current message transfer is done. - * @return True if the transfer is done, false if not - */ - public boolean isMessageTransferred() { - return getRemainingByteCount() == 0; - } - - /** - * returns the current speed of the connection - */ - public double getSpeed() { - return this.speed; - } - - /** - * Returns the amount of bytes to be transferred before ongoing transfer - * is ready or 0 if there's no ongoing transfer or it has finished - * already - * @return the amount of bytes to be transferred - */ - public int getRemainingByteCount() { - int remaining; - - if (msgOnFly == null) { - return 0; - } - - remaining = (int)((this.transferDoneTime - SimClock.getTime()) - * this.speed); - - return (remaining > 0 ? remaining : 0); - } - - /** - * Returns a String presentation of the connection. - */ - public String toString() { - return super.toString() + (isTransferring() ? - " until " + String.format("%.2f", this.transferDoneTime) : ""); - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import routing.MessageRouter; + +/** + * A constant bit-rate connection between two DTN nodes. + */ +public class CBRConnection extends Connection { + private int speed; + private double transferDoneTime; + + /** + * Creates a new connection between nodes and sets the connection + * state to "up". + * @param fromNode The node that initiated the connection + * @param fromInterface The interface that initiated the connection + * @param toNode The node in the other side of the connection + * @param toInterface The interface in the other side of the connection + * @param connectionSpeed Transfer speed of the connection (Bps) when + * the connection is initiated + */ + public CBRConnection(DTNHost fromNode, NetworkInterface fromInterface, + DTNHost toNode, NetworkInterface toInterface, int connectionSpeed) { + super(fromNode, fromInterface, toNode, toInterface); + this.speed = connectionSpeed; + this.transferDoneTime = 0; + + } + + /** + * Sets a message that this connection is currently transferring. If message + * passing is controlled by external events, this method is not needed + * (but then e.g. {@link #finalizeTransfer()} and + * {@link #isMessageTransferred()} will not work either). Only a one message + * at a time can be transferred using one connection. + * @param from The host sending the message + * @param m The message + * @return The value returned by + * {@link MessageRouter#receiveMessage(Message, DTNHost)} + */ + public int startTransfer(DTNHost from, Message m) { + assert this.msgOnFly == null : "Already transferring " + + this.msgOnFly + " from " + this.msgFromNode + " to " + + this.getOtherNode(this.msgFromNode) + ". Can't " + + "start transfer of " + m + " from " + from; + + this.msgFromNode = from; + Message newMessage = m.replicate(); + int retVal = getOtherNode(from).receiveMessage(newMessage, from); + + if (retVal == MessageRouter.RCV_OK) { + this.msgOnFly = newMessage; + this.transferDoneTime = SimClock.getTime() + + (1.0*m.getSize()) / this.speed; + } + + return retVal; + } + + /** + * Aborts the transfer of the currently transferred message. + */ + public void abortTransfer() { + assert msgOnFly != null : "No message to abort at " + msgFromNode; + getOtherNode(msgFromNode).messageAborted(this.msgOnFly.getId(), + msgFromNode,getRemainingByteCount()); + clearMsgOnFly(); + this.transferDoneTime = 0; + } + + /** + * Gets the transferdonetime + */ + public double getTransferDoneTime() { + return transferDoneTime; + } + + /** + * Returns true if the current message transfer is done. + * @return True if the transfer is done, false if not + */ + public boolean isMessageTransferred() { + return getRemainingByteCount() == 0; + } + + /** + * returns the current speed of the connection + */ + public double getSpeed() { + return this.speed; + } + + /** + * Returns the amount of bytes to be transferred before ongoing transfer + * is ready or 0 if there's no ongoing transfer or it has finished + * already + * @return the amount of bytes to be transferred + */ + public int getRemainingByteCount() { + int remaining; + + if (msgOnFly == null) { + return 0; + } + + remaining = (int)((this.transferDoneTime - SimClock.getTime()) + * this.speed); + + return (remaining > 0 ? remaining : 0); + } + + /** + * Returns a String presentation of the connection. + */ + public String toString() { + return super.toString() + (isTransferring() ? + " until " + String.format("%.2f", this.transferDoneTime) : ""); + } + +} diff --git a/core/Connection.java b/core/Connection.java index d6e24d43f..a5092b312 100644 --- a/core/Connection.java +++ b/core/Connection.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package core; @@ -29,7 +29,7 @@ public abstract class Connection { * @param toNode The node in the other side of the connection * @param toInterface The interface in the other side of the connection */ - public Connection(DTNHost fromNode, NetworkInterface fromInterface, + public Connection(DTNHost fromNode, NetworkInterface fromInterface, DTNHost toNode, NetworkInterface toInterface) { this.fromNode = fromNode; this.fromInterface = fromInterface; @@ -48,7 +48,7 @@ public boolean isUp() { return this.isUp; } - /** + /** * Returns true if the connections is transferring a message * @return true if the connections is transferring a message */ @@ -56,7 +56,7 @@ public boolean isTransferring() { return this.msgOnFly != null; } - + /** * Returns true if the given node is the initiator of the connection, false * otherwise @@ -66,7 +66,7 @@ public boolean isTransferring() { public boolean isInitiator(DTNHost node) { return node == this.fromNode; } - + /** * Sets the state of the connection. * @param state True if the connection is up, false if not @@ -78,11 +78,11 @@ public void setUpState(boolean state) { /** * Sets a message that this connection is currently transferring. If message * passing is controlled by external events, this method is not needed - * (but then e.g. {@link #finalizeTransfer()} and + * (but then e.g. {@link #finalizeTransfer()} and * {@link #isMessageTransferred()} will not work either). Only a one message * at a time can be transferred using one connection. * @param m The message - * @return The value returned by + * @return The value returned by * {@link MessageRouter#receiveMessage(Message, DTNHost)} */ public abstract int startTransfer(DTNHost from, Message m); @@ -97,7 +97,7 @@ public void setUpState(boolean state) { * Aborts the transfer of the currently transferred message. */ public void abortTransfer() { - assert msgOnFly != null : "No message to abort at " + msgFromNode; + assert msgOnFly != null : "No message to abort at " + msgFromNode; int bytesRemaining = getRemainingByteCount(); this.bytesTransferred += msgOnFly.getSize() - bytesRemaining; @@ -105,7 +105,7 @@ public void abortTransfer() { getOtherNode(msgFromNode).messageAborted(this.msgOnFly.getId(), msgFromNode, bytesRemaining); clearMsgOnFly(); - } + } /** * Returns the amount of bytes to be transferred before ongoing transfer @@ -121,7 +121,7 @@ public void abortTransfer() { */ protected void clearMsgOnFly() { this.msgOnFly = null; - this.msgFromNode = null; + this.msgFromNode = null; } /** @@ -133,7 +133,7 @@ protected void clearMsgOnFly() { public void finalizeTransfer() { assert this.msgOnFly != null : "Nothing to finalize in " + this; assert msgFromNode != null : "msgFromNode is not set"; - + this.bytesTransferred += msgOnFly.getSize(); getOtherNode(msgFromNode).messageTransferred(this.msgOnFly.getId(), @@ -142,7 +142,7 @@ public void finalizeTransfer() { } /** - * Returns true if the current message transfer is done + * Returns true if the current message transfer is done * @return True if the transfer is done, false if not */ public abstract boolean isMessageTransferred(); @@ -153,21 +153,21 @@ public void finalizeTransfer() { * @return true if the connection is ready to transfer a message */ public boolean isReadyForTransfer() { - return this.isUp && this.msgOnFly == null; + return this.isUp && this.msgOnFly == null; } /** * Gets the message that this connection is currently transferring. * @return The message or null if no message is being transferred - */ + */ public Message getMessage() { return this.msgOnFly; } - /** + /** * Gets the current connection speed */ - public abstract double getSpeed(); + public abstract double getSpeed(); /** * Returns the total amount of bytes this connection has transferred so far @@ -182,7 +182,7 @@ public int getTotalBytesTransferred() { return this.bytesTransferred + this.msgOnFly.getSize(); } else { - return this.bytesTransferred + + return this.bytesTransferred + (msgOnFly.getSize() - getRemainingByteCount()); } } @@ -221,8 +221,8 @@ public NetworkInterface getOtherInterface(NetworkInterface i) { */ public String toString() { return fromNode + "<->" + toNode + " (" + getSpeed()/1000 + " kBps) is " + - (isUp() ? "up":"down") + - (isTransferring() ? " transferring " + this.msgOnFly + + (isUp() ? "up":"down") + + (isTransferring() ? " transferring " + this.msgOnFly + " from " + this.msgFromNode : ""); } diff --git a/core/ConnectionListener.java b/core/ConnectionListener.java index 210978f2e..752fedf17 100644 --- a/core/ConnectionListener.java +++ b/core/ConnectionListener.java @@ -1,27 +1,27 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - -/** - * Interface for classes that want to be informed about connections - * between hosts. - */ -public interface ConnectionListener { - - /** - * Method is called when two hosts are connected. - * @param host1 Host that initiated the connection - * @param host2 Host that was connected to - */ - public void hostsConnected(DTNHost host1, DTNHost host2); - - /** - * Method is called when connection between hosts is disconnected. - * @param host1 Host that initiated the disconnection - * @param host2 Host at the other end of the connection - */ - public void hostsDisconnected(DTNHost host1, DTNHost host2); - -} +package core; + +/** + * Interface for classes that want to be informed about connections + * between hosts. + */ +public interface ConnectionListener { + + /** + * Method is called when two hosts are connected. + * @param host1 Host that initiated the connection + * @param host2 Host that was connected to + */ + public void hostsConnected(DTNHost host1, DTNHost host2); + + /** + * Method is called when connection between hosts is disconnected. + * @param host1 Host that initiated the disconnection + * @param host2 Host at the other end of the connection + */ + public void hostsDisconnected(DTNHost host1, DTNHost host2); + +} diff --git a/core/Coord.java b/core/Coord.java index 002801c57..45b22835e 100644 --- a/core/Coord.java +++ b/core/Coord.java @@ -1,156 +1,156 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - -/** - * Class to hold 2D coordinates and perform simple arithmetics and - * transformations - */ -public class Coord implements Cloneable, Comparable { - private double x; - private double y; - - /** - * Constructor. - * @param x Initial X-coordinate - * @param y Initial Y-coordinate - */ - public Coord(double x, double y) { - setLocation(x,y); - } - - /** - * Sets the location of this coordinate object - * @param x The x coordinate to set - * @param y The y coordinate to set - */ - public void setLocation(double x, double y) { - this.x = x; - this.y = y; - } - - /** - * Sets this coordinate's location to be equal to other - * coordinates location - * @param c The other coordinate - */ - public void setLocation(Coord c) { - this.x = c.x; - this.y = c.y; - } - - /** - * Moves the point by dx and dy - * @param dx How much to move the point in X-direction - * @param dy How much to move the point in Y-direction - */ - public void translate(double dx, double dy) { - this.x += dx; - this.y += dy; - } - - /** - * Returns the distance to another coordinate - * @param other The other coordinate - * @return The distance between this and another coordinate - */ - public double distance(Coord other) { - double dx = this.x - other.x; - double dy = this.y - other.y; - - return Math.sqrt(dx*dx + dy*dy); - } - - /** - * Returns the x coordinate - * @return x coordinate - */ - public double getX() { - return this.x; - } - - /** - * Returns the y coordinate - * @return y coordinate - */ - public double getY() { - return this.y; - } - - /** - * Returns a text representation of the coordinate (rounded to 2 decimals) - * @return a text representation of the coordinate - */ - public String toString() { - return String.format("(%.2f,%.2f)",x,y); - } - - /** - * Returns a clone of this coordinate - */ - public Coord clone() { - Coord clone = null; - try { - clone = (Coord) super.clone(); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - System.exit(-1); - } - return clone; - } - - /** - * Checks if this coordinate's location is equal to other coordinate's - * @param c The other coordinate - * @return True if locations are the same - */ - public boolean equals(Coord c) { - if (c == this) { - return true; - } - else { - return (x == c.x && y == c.y); // XXX: == for doubles... - } - } - - @Override +package core; + +/** + * Class to hold 2D coordinates and perform simple arithmetics and + * transformations + */ +public class Coord implements Cloneable, Comparable { + private double x; + private double y; + + /** + * Constructor. + * @param x Initial X-coordinate + * @param y Initial Y-coordinate + */ + public Coord(double x, double y) { + setLocation(x,y); + } + + /** + * Sets the location of this coordinate object + * @param x The x coordinate to set + * @param y The y coordinate to set + */ + public void setLocation(double x, double y) { + this.x = x; + this.y = y; + } + + /** + * Sets this coordinate's location to be equal to other + * coordinates location + * @param c The other coordinate + */ + public void setLocation(Coord c) { + this.x = c.x; + this.y = c.y; + } + + /** + * Moves the point by dx and dy + * @param dx How much to move the point in X-direction + * @param dy How much to move the point in Y-direction + */ + public void translate(double dx, double dy) { + this.x += dx; + this.y += dy; + } + + /** + * Returns the distance to another coordinate + * @param other The other coordinate + * @return The distance between this and another coordinate + */ + public double distance(Coord other) { + double dx = this.x - other.x; + double dy = this.y - other.y; + + return Math.sqrt(dx*dx + dy*dy); + } + + /** + * Returns the x coordinate + * @return x coordinate + */ + public double getX() { + return this.x; + } + + /** + * Returns the y coordinate + * @return y coordinate + */ + public double getY() { + return this.y; + } + + /** + * Returns a text representation of the coordinate (rounded to 2 decimals) + * @return a text representation of the coordinate + */ + public String toString() { + return String.format("(%.2f,%.2f)",x,y); + } + + /** + * Returns a clone of this coordinate + */ + public Coord clone() { + Coord clone = null; + try { + clone = (Coord) super.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + System.exit(-1); + } + return clone; + } + + /** + * Checks if this coordinate's location is equal to other coordinate's + * @param c The other coordinate + * @return True if locations are the same + */ + public boolean equals(Coord c) { + if (c == this) { + return true; + } + else { + return (x == c.x && y == c.y); // XXX: == for doubles... + } + } + + @Override public boolean equals(Object o) { - if (o == null) return false; - return equals((Coord) o); - } - - /** - * Returns a hash code for this coordinate - * (actually a hash of the String made of the coordinates) - */ - public int hashCode() { - return (x+","+y).hashCode(); - } - - /** - * Compares this coordinate to other coordinate. Coordinate whose y - * value is smaller comes first and if y values are equal, the one with - * smaller x value comes first. - * @return -1, 0 or 1 if this node is before, in the same place or - * after the other coordinate - */ - public int compareTo(Coord other) { - if (this.y < other.y) { - return -1; - } - else if (this.y > other.y) { - return 1; - } - else if (this.x < other.x) { - return -1; - } - else if (this.x > other.x) { - return 1; - } - else { - return 0; - } - } -} + if (o == null) return false; + return equals((Coord) o); + } + + /** + * Returns a hash code for this coordinate + * (actually a hash of the String made of the coordinates) + */ + public int hashCode() { + return (x+","+y).hashCode(); + } + + /** + * Compares this coordinate to other coordinate. Coordinate whose y + * value is smaller comes first and if y values are equal, the one with + * smaller x value comes first. + * @return -1, 0 or 1 if this node is before, in the same place or + * after the other coordinate + */ + public int compareTo(Coord other) { + if (this.y < other.y) { + return -1; + } + else if (this.y > other.y) { + return 1; + } + else if (this.x < other.x) { + return -1; + } + else if (this.x > other.x) { + return 1; + } + else { + return 0; + } + } +} diff --git a/core/DTN2Manager.java b/core/DTN2Manager.java index 9e1592ecd..80c6d607d 100644 --- a/core/DTN2Manager.java +++ b/core/DTN2Manager.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package core; @@ -20,7 +20,7 @@ import fi.tkk.netlab.dtn.ecla.Bundle; import fi.tkk.netlab.dtn.ecla.CLAParser; -/** +/** * Manages the external convergence layer connections to dtnd. * Parses the configuration file and sets up the CLAParsers * and EID->host mappings. @@ -29,14 +29,14 @@ public class DTN2Manager { private static Map CLAs = null; /** Mapping from EID to DTNHost */ - private static Collection EID_to_host = null; + private static Collection EID_to_host = null; /** Set of all bundles in the simulator */ private static Map bundles = null; /** Reporter object that passes messages from ONE to dtnd */ private static DTN2Reporter reporter = null; /** Events object that passes messages from dtnd to ONE */ private static DTN2Events events = null; - + /** * EID to DTNHost mapping elements. */ @@ -50,7 +50,7 @@ public EIDHost(String eid, int host_id, DTNHost host) { this.host_id = host_id; } } - + /** * Sets up the dtnd connections by parsing the configuration file * defined in the DTN2.configFile setting. @@ -65,16 +65,16 @@ public static void setup(World world) { String[] attrs; int nodeID, dtnd_port, console_port; String nodeEID, dtnd_host; - + DTN2Manager.CLAs = new HashMap(); DTN2Manager.EID_to_host = new LinkedList(); DTN2Manager.bundles = new HashMap(); - + // Check if DTN2Reporter and DTN2Events have been loaded. // If not, we do nothing here. if (DTN2Manager.reporter==null || DTN2Manager.events==null) return; - + // Get input stream from the settings file. Settings conf = new Settings("DTN2"); String fname; @@ -94,12 +94,12 @@ public static void setup(World world) { +fname+"'"); return; } - + // Create a directory to hold copies of the bundles f = new File("bundles"); if (!f.exists()) f.mkdir(); - + // Parse config file try { s = in.readLine(); @@ -114,21 +114,21 @@ public static void setup(World world) { dtnd_host = attrs[2]; dtnd_port = Integer.parseInt(attrs[3]); console_port = Integer.parseInt(attrs[4]); - + // Find the host DTNHost h = world.getNodeByAddress(nodeID); // Add to the EID -> Host mapping - DTN2Manager.EIDHost e = new DTN2Manager.EIDHost(nodeEID, + DTN2Manager.EIDHost e = new DTN2Manager.EIDHost(nodeEID, nodeID, h); DTN2Manager.EID_to_host.add(e); - + // Configure and start the CLA CLAParser p; p = new CLAParser(dtnd_host, dtnd_port, "ONE"); - DTN2Events.ParserHandler ph = + DTN2Events.ParserHandler ph = DTN2Manager.events.getParserHandler(nodeID, dtnd_host, - console_port); + console_port); p.setListener(ph); Thread t = new Thread(p); t.start(); @@ -142,8 +142,8 @@ public static void setup(World world) { } } } - - + + /** * Sets the DTN2Reporter object used to pass messages from ONE * to dtnd. @@ -154,15 +154,15 @@ public static void setup(World world) { public static void setReporter(DTN2Reporter reporter) { DTN2Manager.reporter = reporter; } - + /** * Returns reference to the DTN2Reporter object. * @return reference to the active DTN2Reporter object - */ + */ public static DTN2Reporter getReporter() { return DTN2Manager.reporter; } - + /** * Sets the DTN2Events object. * @param events the active events object to use @@ -170,15 +170,15 @@ public static DTN2Reporter getReporter() { public static void setEvents(DTN2Events events) { DTN2Manager.events = events; } - - /** + + /** * Returns the DTN2Events object. * @return the currently active events object. */ public static DTN2Events getEvents() { return DTN2Manager.events; } - + /** * Returns the ECL parser associated with the host. * @param host the host who's parser to return @@ -187,8 +187,8 @@ public static DTN2Events getEvents() { public static CLAParser getParser(DTNHost host) { return DTN2Manager.CLAs.get(host); } - - /** + + /** * Returns a Collection of DTNHost * objects corresponding to the given EID. * @param EID EID of the host @@ -201,7 +201,7 @@ public static Collection getHosts(String EID) { } return c; } - + /** * Stores a reference to a bundle corresponding to the given message. * @param id the id of the message @@ -210,8 +210,8 @@ public static Collection getHosts(String EID) { public static void addBundle(String id, Bundle bundle) { DTN2Manager.bundles.put(id, bundle); } - - /** + + /** * Returns the bundle associated with the given message id. * @param id the message id * @return the bundle associated with the message diff --git a/core/DTNHost.java b/core/DTNHost.java index 6a8c6c934..a230f22fd 100644 --- a/core/DTNHost.java +++ b/core/DTNHost.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - +package core; + import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -12,46 +12,46 @@ import movement.Path; import routing.MessageRouter; import routing.util.RoutingInfo; - -/** - * A DTN capable host. - */ -public class DTNHost implements Comparable { + +/** + * A DTN capable host. + */ +public class DTNHost implements Comparable { private static int nextAddress = 0; private int address; - private Coord location; // where is the host - private Coord destination; // where is it going - - private MessageRouter router; - private MovementModel movement; - private Path path; - private double speed; - private double nextTimeToMove; - private String name; - private List msgListeners; - private List movListeners; + private Coord location; // where is the host + private Coord destination; // where is it going + + private MessageRouter router; + private MovementModel movement; + private Path path; + private double speed; + private double nextTimeToMove; + private String name; + private List msgListeners; + private List movListeners; private List net; - private ModuleCommunicationBus comBus; + private ModuleCommunicationBus comBus; static { DTNSim.registerForReset(DTNHost.class.getCanonicalName()); reset(); - } - /** - * Creates a new DTNHost. + } + /** + * Creates a new DTNHost. * @param msgLs Message listeners - * @param movLs Movement listeners - * @param groupId GroupID of this host + * @param movLs Movement listeners + * @param groupId GroupID of this host * @param interf List of NetworkInterfaces for the class * @param comBus Module communication bus object - * @param mmProto Prototype of the movement model of this host - * @param mRouterProto Prototype of the message router of this host - */ + * @param mmProto Prototype of the movement model of this host + * @param mRouterProto Prototype of the message router of this host + */ public DTNHost(List msgLs, List movLs, String groupId, List interf, - ModuleCommunicationBus comBus, + ModuleCommunicationBus comBus, MovementModel mmProto, MessageRouter mRouterProto) { this.comBus = comBus; this.location = new Coord(0,0); @@ -63,39 +63,39 @@ public DTNHost(List msgLs, NetworkInterface ni = i.replicate(); ni.setHost(this); net.add(ni); - } + } // TODO - think about the names of the interfaces and the nodes //this.name = groupId + ((NetworkInterface)net.get(1)).getAddress(); - this.msgListeners = msgLs; - this.movListeners = movLs; - - // create instances by replicating the prototypes + this.msgListeners = msgLs; + this.movListeners = movLs; + + // create instances by replicating the prototypes this.movement = mmProto.replicate(); this.movement.setComBus(comBus); - this.movement.setHost(this); - setRouter(mRouterProto.replicate()); - - this.location = movement.getInitialLocation(); - - this.nextTimeToMove = movement.nextPathAvailable(); - this.path = null; - - if (movLs != null) { // inform movement listeners about the location - for (MovementListener l : movLs) { - l.initialLocation(this, this.location); - } - } - } - + this.movement.setHost(this); + setRouter(mRouterProto.replicate()); + + this.location = movement.getInitialLocation(); + + this.nextTimeToMove = movement.nextPathAvailable(); + this.path = null; + + if (movLs != null) { // inform movement listeners about the location + for (MovementListener l : movLs) { + l.initialLocation(this, this.location); + } + } + } + /** * Returns a new network interface address and increments the address for * subsequent calls. * @return The next address. */ private synchronized static int getNextAddress() { - return nextAddress++; + return nextAddress++; } /** @@ -103,16 +103,16 @@ private synchronized static int getNextAddress() { */ public static void reset() { nextAddress = 0; - } - - /** - * Returns true if this node is actively moving (false if not) - * @return true if this node is actively moving (false if not) - */ - public boolean isMovementActive() { - return this.movement.isActive(); - } - + } + + /** + * Returns true if this node is actively moving (false if not) + * @return true if this node is actively moving (false if not) + */ + public boolean isMovementActive() { + return this.movement.isActive(); + } + /** * Returns true if this node's radio is active (false if not) * @return true if this node's radio is active (false if not) @@ -120,32 +120,32 @@ public boolean isMovementActive() { public boolean isRadioActive() { /* TODO: make this work for multiple interfaces */ return this.getInterface(1).isActive(); - } - - /** - * Set a router for this host - * @param router The router to set - */ - private void setRouter(MessageRouter router) { - router.init(this, msgListeners); - this.router = router; - } - - /** - * Returns the router of this host - * @return the router of this host - */ - public MessageRouter getRouter() { - return this.router; - } - - /** - * Returns the network-layer address of this host. - */ - public int getAddress() { - return this.address; - } - + } + + /** + * Set a router for this host + * @param router The router to set + */ + private void setRouter(MessageRouter router) { + router.init(this, msgListeners); + this.router = router; + } + + /** + * Returns the router of this host + * @return the router of this host + */ + public MessageRouter getRouter() { + return this.router; + } + + /** + * Returns the network-layer address of this host. + */ + public int getAddress() { + return this.address; + } + /** * Returns this hosts's ModuleCommunicationBus * @return this hosts's ModuleCommunicationBus @@ -153,7 +153,7 @@ public int getAddress() { public ModuleCommunicationBus getComBus() { return this.comBus; } - + /** * Informs the router of this host about state change in a connection * object. @@ -166,90 +166,90 @@ public void connectionUp(Connection con) { public void connectionDown(Connection con) { this.router.changedConnection(con); } - - /** - * Returns a copy of the list of connections this host has with other hosts - * @return a copy of the list of connections this host has with other hosts - */ - public List getConnections() { + + /** + * Returns a copy of the list of connections this host has with other hosts + * @return a copy of the list of connections this host has with other hosts + */ + public List getConnections() { List lc = new ArrayList(); for (NetworkInterface i : net) { lc.addAll(i.getConnections()); } - return lc; - } - - /** - * Returns the current location of this host. - * @return The location - */ - public Coord getLocation() { - return this.location; - } - - /** - * Returns the Path this node is currently traveling or null if no - * path is in use at the moment. - * @return The path this node is traveling - */ - public Path getPath() { - return this.path; - } - - - /** - * Sets the Node's location overriding any location set by movement model - * @param location The location to set - */ - public void setLocation(Coord location) { - this.location = location.clone(); - } - - /** - * Sets the Node's name overriding the default name (groupId + netAddress) - * @param name The name to set - */ - public void setName(String name) { - this.name = name; - } - - /** - * Returns the messages in a collection. - * @return Messages in a collection - */ - public Collection getMessageCollection() { - return this.router.getMessageCollection(); - } - - /** - * Returns the number of messages this node is carrying. - * @return How many messages the node is carrying currently. - */ - public int getNrofMessages() { - return this.router.getNrofMessages(); - } - - /** - * Returns the buffer occupancy percentage. Occupancy is 0 for empty - * buffer but can be over 100 if a created message is bigger than buffer - * space that could be freed. - * @return Buffer occupancy percentage - */ - public double getBufferOccupancy() { - double bSize = router.getBufferSize(); - double freeBuffer = router.getFreeBufferSize(); - return 100*((bSize-freeBuffer)/bSize); - } - - /** - * Returns routing info of this host's router. - * @return The routing info. - */ - public RoutingInfo getRoutingInfo() { - return this.router.getRoutingInfo(); - } + return lc; + } + + /** + * Returns the current location of this host. + * @return The location + */ + public Coord getLocation() { + return this.location; + } + + /** + * Returns the Path this node is currently traveling or null if no + * path is in use at the moment. + * @return The path this node is traveling + */ + public Path getPath() { + return this.path; + } + + + /** + * Sets the Node's location overriding any location set by movement model + * @param location The location to set + */ + public void setLocation(Coord location) { + this.location = location.clone(); + } + + /** + * Sets the Node's name overriding the default name (groupId + netAddress) + * @param name The name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the messages in a collection. + * @return Messages in a collection + */ + public Collection getMessageCollection() { + return this.router.getMessageCollection(); + } + + /** + * Returns the number of messages this node is carrying. + * @return How many messages the node is carrying currently. + */ + public int getNrofMessages() { + return this.router.getNrofMessages(); + } + + /** + * Returns the buffer occupancy percentage. Occupancy is 0 for empty + * buffer but can be over 100 if a created message is bigger than buffer + * space that could be freed. + * @return Buffer occupancy percentage + */ + public double getBufferOccupancy() { + double bSize = router.getBufferSize(); + double freeBuffer = router.getFreeBufferSize(); + return 100*((bSize-freeBuffer)/bSize); + } + + /** + * Returns routing info of this host's router. + * @return The routing info. + */ + public RoutingInfo getRoutingInfo() { + return this.router.getRoutingInfo(); + } /** * Returns the interface objects of the node @@ -266,7 +266,7 @@ public NetworkInterface getInterface(int interfaceNo) { try { ni = net.get(interfaceNo-1); } catch (IndexOutOfBoundsException ex) { - throw new SimError("No such interface: "+interfaceNo + + throw new SimError("No such interface: "+interfaceNo + " at " + this); } return ni; @@ -281,13 +281,13 @@ protected NetworkInterface getInterface(String interfacetype) { return ni; } } - return null; + return null; } /** * Force a connection event */ - public void forceConnection(DTNHost anotherHost, String interfaceId, + public void forceConnection(DTNHost anotherHost, String interfaceId, boolean up) { NetworkInterface ni; NetworkInterface no; @@ -301,11 +301,11 @@ public void forceConnection(DTNHost anotherHost, String interfaceId, } else { ni = getInterface(1); no = anotherHost.getInterface(1); - - assert (ni.getInterfaceType().equals(no.getInterfaceType())) : + + assert (ni.getInterfaceType().equals(no.getInterfaceType())) : "Interface types do not match. Please specify interface type explicitly"; } - + if (up) { ni.createConnection(no); } else { @@ -323,25 +323,25 @@ public void connect(DTNHost h) { } /** - * Updates node's network layer and router. + * Updates node's network layer and router. * @param simulateConnections Should network layer be updated too - */ + */ public void update(boolean simulateConnections) { if (!isRadioActive()) { // Make sure inactive nodes don't have connections tearDownAllConnections(); return; } - + if (simulateConnections) { for (NetworkInterface i : net) { i.update(); } } - this.router.update(); + this.router.update(); } - - /** + + /** * Tears down all connections for this host. */ private void tearDownAllConnections() { @@ -349,7 +349,7 @@ private void tearDownAllConnections() { // Get all connections for the interface List conns = i.getConnections(); if (conns.size() == 0) continue; - + // Destroy all connections List removeList = new ArrayList(conns.size()); @@ -360,177 +360,177 @@ private void tearDownAllConnections() { i.destroyConnection(inf); } } - } - - /** - * Moves the node towards the next waypoint or waits if it is - * not time to move yet - * @param timeIncrement How long time the node moves - */ - public void move(double timeIncrement) { + } + + /** + * Moves the node towards the next waypoint or waits if it is + * not time to move yet + * @param timeIncrement How long time the node moves + */ + public void move(double timeIncrement) { double possibleMovement; double distance; double dx, dy; - if (!isMovementActive() || SimClock.getTime() < this.nextTimeToMove) { - return; - } - if (this.destination == null) { - if (!setNextWaypoint()) { - return; - } - } - - possibleMovement = timeIncrement * speed; - distance = this.location.distance(this.destination); - - while (possibleMovement >= distance) { - // node can move past its next destination - this.location.setLocation(this.destination); // snap to destination - possibleMovement -= distance; - if (!setNextWaypoint()) { // get a new waypoint - return; // no more waypoints left - } - distance = this.location.distance(this.destination); - } - - // move towards the point for possibleMovement amount - dx = (possibleMovement/distance) * (this.destination.getX() - - this.location.getX()); - dy = (possibleMovement/distance) * (this.destination.getY() - - this.location.getY()); - this.location.translate(dx, dy); - } - - /** - * Sets the next destination and speed to correspond the next waypoint - * on the path. - * @return True if there was a next waypoint to set, false if node still - * should wait - */ - private boolean setNextWaypoint() { - if (path == null) { - path = movement.getPath(); - } - - if (path == null || !path.hasNext()) { - this.nextTimeToMove = movement.nextPathAvailable(); - this.path = null; - return false; - } - - this.destination = path.getNextWaypoint(); - this.speed = path.getSpeed(); - - if (this.movListeners != null) { - for (MovementListener l : this.movListeners) { - l.newDestination(this, this.destination, this.speed); - } - } - - return true; - } - - /** - * Sends a message from this host to another host - * @param id Identifier of the message - * @param to Host the message should be sent to - */ - public void sendMessage(String id, DTNHost to) { - this.router.sendMessage(id, to); - } - - /** - * Start receiving a message from another host - * @param m The message - * @param from Who the message is from - * @return The value returned by - * {@link MessageRouter#receiveMessage(Message, DTNHost)} - */ - public int receiveMessage(Message m, DTNHost from) { - int retVal = this.router.receiveMessage(m, from); + if (!isMovementActive() || SimClock.getTime() < this.nextTimeToMove) { + return; + } + if (this.destination == null) { + if (!setNextWaypoint()) { + return; + } + } + + possibleMovement = timeIncrement * speed; + distance = this.location.distance(this.destination); + + while (possibleMovement >= distance) { + // node can move past its next destination + this.location.setLocation(this.destination); // snap to destination + possibleMovement -= distance; + if (!setNextWaypoint()) { // get a new waypoint + return; // no more waypoints left + } + distance = this.location.distance(this.destination); + } + + // move towards the point for possibleMovement amount + dx = (possibleMovement/distance) * (this.destination.getX() - + this.location.getX()); + dy = (possibleMovement/distance) * (this.destination.getY() - + this.location.getY()); + this.location.translate(dx, dy); + } + + /** + * Sets the next destination and speed to correspond the next waypoint + * on the path. + * @return True if there was a next waypoint to set, false if node still + * should wait + */ + private boolean setNextWaypoint() { + if (path == null) { + path = movement.getPath(); + } + + if (path == null || !path.hasNext()) { + this.nextTimeToMove = movement.nextPathAvailable(); + this.path = null; + return false; + } + + this.destination = path.getNextWaypoint(); + this.speed = path.getSpeed(); + + if (this.movListeners != null) { + for (MovementListener l : this.movListeners) { + l.newDestination(this, this.destination, this.speed); + } + } + + return true; + } + + /** + * Sends a message from this host to another host + * @param id Identifier of the message + * @param to Host the message should be sent to + */ + public void sendMessage(String id, DTNHost to) { + this.router.sendMessage(id, to); + } + + /** + * Start receiving a message from another host + * @param m The message + * @param from Who the message is from + * @return The value returned by + * {@link MessageRouter#receiveMessage(Message, DTNHost)} + */ + public int receiveMessage(Message m, DTNHost from) { + int retVal = this.router.receiveMessage(m, from); if (retVal == MessageRouter.RCV_OK) { m.addNodeOnPath(this); // add this node on the messages path } - return retVal; - } - - /** - * Requests for deliverable message from this host to be sent trough a - * connection. - * @param con The connection to send the messages trough - * @return True if this host started a transfer, false if not - */ - public boolean requestDeliverableMessages(Connection con) { - return this.router.requestDeliverableMessages(con); - } - - /** - * Informs the host that a message was successfully transferred. - * @param id Identifier of the message - * @param from From who the message was from - */ - public void messageTransferred(String id, DTNHost from) { - this.router.messageTransferred(id, from); - } - - /** - * Informs the host that a message transfer was aborted. - * @param id Identifier of the message + return retVal; + } + + /** + * Requests for deliverable message from this host to be sent trough a + * connection. + * @param con The connection to send the messages trough + * @return True if this host started a transfer, false if not + */ + public boolean requestDeliverableMessages(Connection con) { + return this.router.requestDeliverableMessages(con); + } + + /** + * Informs the host that a message was successfully transferred. + * @param id Identifier of the message + * @param from From who the message was from + */ + public void messageTransferred(String id, DTNHost from) { + this.router.messageTransferred(id, from); + } + + /** + * Informs the host that a message transfer was aborted. + * @param id Identifier of the message * @param from From who the message was from * @param bytesRemaining Nrof bytes that were left before the transfer - * would have been ready; or -1 if the number of bytes is not known - */ - public void messageAborted(String id, DTNHost from, int bytesRemaining) { - this.router.messageAborted(id, from, bytesRemaining); - } - - /** + * would have been ready; or -1 if the number of bytes is not known + */ + public void messageAborted(String id, DTNHost from, int bytesRemaining) { + this.router.messageAborted(id, from, bytesRemaining); + } + + /** * Creates a new message to this host's router - * @param m The message to create - */ + * @param m The message to create + */ public void createNewMessage(Message m) { - this.router.createNewMessage(m); - } - - /** - * Deletes a message from this host - * @param id Identifier of the message - * @param drop True if the message is deleted because of "dropping" - * (e.g. buffer is full) or false if it was deleted for some other reason - * (e.g. the message got delivered to final destination). This effects the - * way the removing is reported to the message listeners. - */ - public void deleteMessage(String id, boolean drop) { - this.router.deleteMessage(id, drop); - } - - /** - * Returns a string presentation of the host. - * @return Host's name - */ - public String toString() { - return name; - } - - /** + this.router.createNewMessage(m); + } + + /** + * Deletes a message from this host + * @param id Identifier of the message + * @param drop True if the message is deleted because of "dropping" + * (e.g. buffer is full) or false if it was deleted for some other reason + * (e.g. the message got delivered to final destination). This effects the + * way the removing is reported to the message listeners. + */ + public void deleteMessage(String id, boolean drop) { + this.router.deleteMessage(id, drop); + } + + /** + * Returns a string presentation of the host. + * @return Host's name + */ + public String toString() { + return name; + } + + /** * Checks if a host is the same as this host by comparing the object - * reference - * @param otherHost The other host - * @return True if the hosts objects are the same object - */ - public boolean equals(DTNHost otherHost) { - return this == otherHost; - } - - /** - * Compares two DTNHosts by their addresses. - * @see Comparable#compareTo(Object) - */ - public int compareTo(DTNHost h) { - return this.getAddress() - h.getAddress(); - } - -} + * reference + * @param otherHost The other host + * @return True if the hosts objects are the same object + */ + public boolean equals(DTNHost otherHost) { + return this == otherHost; + } + + /** + * Compares two DTNHosts by their addresses. + * @see Comparable#compareTo(Object) + */ + public int compareTo(DTNHost h) { + return this.getAddress() - h.getAddress(); + } + +} diff --git a/core/DTNSim.java b/core/DTNSim.java index bfa3307e7..cd91a6477 100644 --- a/core/DTNSim.java +++ b/core/DTNSim.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package core; import gui.DTNSimGUI; @@ -10,32 +10,32 @@ import java.util.List; import ui.DTNSimTextUI; - -/** - * Simulator's main class - */ -public class DTNSim { - /** If this option ({@value}) is given to program, batch mode and - * Text UI are used*/ + +/** + * Simulator's main class + */ +public class DTNSim { + /** If this option ({@value}) is given to program, batch mode and + * Text UI are used*/ public static final String BATCH_MODE_FLAG = "-b"; /** Delimiter for batch mode index range values (colon) */ public static final String RANGE_DELIMETER = ":"; - + /** Name of the static method that all resettable classes must have * @see #registerForReset(String) */ public static final String RESET_METHOD_NAME = "reset"; /** List of class names that should be reset between batch runs */ private static List> resetList = new ArrayList>(); - + /** * Starts the user interface with given arguments. * If first argument is {@link #BATCH_MODE_FLAG}, the batch mode and text UI * is started. The batch mode option must be followed by the number of runs, - * or a with a combination of starting run and the number of runs, + * or a with a combination of starting run and the number of runs, * delimited with a {@value #RANGE_DELIMETER}. Different settings from run - * arrays are used for different runs (see - * {@link Settings#setRunIndex(int)}). Following arguments are the settings - * files for the simulation run (if any). For GUI mode, the number before + * arrays are used for different runs (see + * {@link Settings#setRunIndex(int)}). Following arguments are the settings + * files for the simulation run (if any). For GUI mode, the number before * settings files (if given) is the run index to use for that run. * @param args Command line arguments */ @@ -48,7 +48,7 @@ public static void main(String[] args) { /* set US locale to parse decimals in consistent way */ java.util.Locale.setDefault(java.util.Locale.US); - + if (args.length > 0) { if (args[0].equals(BATCH_MODE_FLAG)) { batchMode = true; @@ -60,7 +60,7 @@ public static void main(String[] args) { firstConfIndex = 2; } } - else { /* GUI mode */ + else { /* GUI mode */ try { /* is there a run index for the GUI mode ? */ guiIndex = Integer.parseInt(args[0]); firstConfIndex = 1; @@ -73,9 +73,9 @@ public static void main(String[] args) { else { confFiles = new String[] {null}; } - + initSettings(confFiles, firstConfIndex); - + if (batchMode) { long startTime = System.currentTimeMillis(); for (int i=nrofRuns[0]; icore.SimClock + * @param className Full name (i.e., containing the packet path) + * of the class to register. For example: core.SimClock */ public static void registerForReset(String className) { Class c = null; @@ -146,19 +146,19 @@ public static void registerForReset(String className) { c = Class.forName(className); c.getMethod(RESET_METHOD_NAME); } catch (ClassNotFoundException e) { - System.err.println("Can't register class " + className + + System.err.println("Can't register class " + className + " for resetting; class not found"); System.exit(-1); - + } catch (NoSuchMethodException e) { - System.err.println("Can't register class " + className + + System.err.println("Can't register class " + className + " for resetting; class doesn't contain resetting method"); System.exit(-1); } resetList.add(c); } - + /** * Resets all registered classes. */ @@ -174,18 +174,18 @@ private static void resetForNextRun() { } } } - + /** - * Parses the number of runs, and an optional starting run index, from a + * Parses the number of runs, and an optional starting run index, from a * command line argument * @param arg The argument to parse * @return The first and (last_run_index - 1) in an array */ private static int[] parseNrofRuns(String arg) { - int val[] = {0,1}; + int val[] = {0,1}; try { if (arg.contains(RANGE_DELIMETER)) { - val[0] = Integer.parseInt(arg.substring(0, + val[0] = Integer.parseInt(arg.substring(0, arg.indexOf(RANGE_DELIMETER))) - 1; val[1] = Integer.parseInt(arg.substring(arg. indexOf(RANGE_DELIMETER) + 1, arg.length())); @@ -193,29 +193,29 @@ private static int[] parseNrofRuns(String arg) { else { val[0] = 0; val[1] = Integer.parseInt(arg); - } + } } catch (NumberFormatException e) { System.err.println("Invalid argument '" + arg + "' for" + " number of runs"); - System.err.println("The argument must be either a single value, " + - "or a range of values (e.g., '2:5'). Note that this " + + System.err.println("The argument must be either a single value, " + + "or a range of values (e.g., '2:5'). Note that this " + "option has changed in version 1.3."); System.exit(-1); } - + if (val[0] < 0) { System.err.println("Starting run value can't be smaller than 1"); System.exit(-1); } if (val[0] >= val[1]) { - System.err.println("Starting run value can't be bigger than the " + + System.err.println("Starting run value can't be bigger than the " + "last run value"); - System.exit(-1); + System.exit(-1); } - + return val; } - + /** * Prints text to stdout * @param txt Text to print diff --git a/core/Debug.java b/core/Debug.java index 722b79fde..b0546a1f9 100644 --- a/core/Debug.java +++ b/core/Debug.java @@ -1,115 +1,115 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - +package core; + import java.io.PrintStream; - -/** - * Debugging info printer with time stamping. This class is not to be actively - * used but convenient for temporary debugging. - */ -public class Debug { - private static PrintStream out = System.out; - private static int debugLevel = 0; - private static long timingStart = -1; - private static String timingCause; - - /** - * Sets the current debug level (smaller level -> more messages) - * @param level The level to set - */ - public void setDebugLevel(int level) { - debugLevel = level; - } - - /** - * Sets print stream of debug output. - * @param outStrm The stream - */ - public void setPrintStream(PrintStream outStrm) { - out = outStrm; - } - - /** - * Prints text to output with level 0 - * @param txt text to print - */ - public static void p(String txt) { - p(txt, 0, false); - } - - /** - * Prints text to output given with level - * @param level The debug level - * @param txt text to print - */ - public static void p(String txt, int level) { - p(txt,level, false); - } - - - /** - * Debug print with a timestamp - * @param txt Text to print - * @param level Debug level - */ - public static void pt(String txt, int level) { - p(txt,level,true); - } - - /** - * Debug print with a timestamp and 0 level - * @param txt Text to print - */ - public static void pt(String txt) { - p(txt,0,true); - } - - /** - * Print text to debug output. - * @param txt The text to print - * @param level The debug level (only messages with level >= debugLevel - * are printed) - * @param timestamp If true, text is (sim)timestamped - */ - public static void p(String txt, int level, boolean timestamp) { - String time = ""; - int simTime = SimClock.getIntTime(); - if (level < debugLevel) { - return; - } - - if (timestamp) { - time = "[@"+simTime+"]"; - } - out.println("D" + time + ": " + txt); - } - - /** - * Start timing an action. - * @see #doneTiming() - */ - public static void startTiming(String cause) { - if (timingStart != -1) { - doneTiming(); - } - timingCause = cause; - timingStart = System.currentTimeMillis(); - } - - /** - * End timing an action. Information how long the action took is - * printed to debug stream. - * @see #startTiming(String) - */ - public static void doneTiming() { - long end = System.currentTimeMillis(); - long diff = end-timingStart; - if (end-timingStart > 0) - pt(timingCause + " took "+ diff/1000.0 + "s" ); - - timingStart = -1; - } -} + +/** + * Debugging info printer with time stamping. This class is not to be actively + * used but convenient for temporary debugging. + */ +public class Debug { + private static PrintStream out = System.out; + private static int debugLevel = 0; + private static long timingStart = -1; + private static String timingCause; + + /** + * Sets the current debug level (smaller level -> more messages) + * @param level The level to set + */ + public void setDebugLevel(int level) { + debugLevel = level; + } + + /** + * Sets print stream of debug output. + * @param outStrm The stream + */ + public void setPrintStream(PrintStream outStrm) { + out = outStrm; + } + + /** + * Prints text to output with level 0 + * @param txt text to print + */ + public static void p(String txt) { + p(txt, 0, false); + } + + /** + * Prints text to output given with level + * @param level The debug level + * @param txt text to print + */ + public static void p(String txt, int level) { + p(txt,level, false); + } + + + /** + * Debug print with a timestamp + * @param txt Text to print + * @param level Debug level + */ + public static void pt(String txt, int level) { + p(txt,level,true); + } + + /** + * Debug print with a timestamp and 0 level + * @param txt Text to print + */ + public static void pt(String txt) { + p(txt,0,true); + } + + /** + * Print text to debug output. + * @param txt The text to print + * @param level The debug level (only messages with level >= debugLevel + * are printed) + * @param timestamp If true, text is (sim)timestamped + */ + public static void p(String txt, int level, boolean timestamp) { + String time = ""; + int simTime = SimClock.getIntTime(); + if (level < debugLevel) { + return; + } + + if (timestamp) { + time = "[@"+simTime+"]"; + } + out.println("D" + time + ": " + txt); + } + + /** + * Start timing an action. + * @see #doneTiming() + */ + public static void startTiming(String cause) { + if (timingStart != -1) { + doneTiming(); + } + timingCause = cause; + timingStart = System.currentTimeMillis(); + } + + /** + * End timing an action. Information how long the action took is + * printed to debug stream. + * @see #startTiming(String) + */ + public static void doneTiming() { + long end = System.currentTimeMillis(); + long diff = end-timingStart; + if (end-timingStart > 0) + pt(timingCause + " took "+ diff/1000.0 + "s" ); + + timingStart = -1; + } +} diff --git a/core/Message.java b/core/Message.java index 60b48b75e..d037b890b 100644 --- a/core/Message.java +++ b/core/Message.java @@ -1,268 +1,268 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - +package core; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; - -/** - * A message that is created at a node or passed between nodes. - */ -public class Message implements Comparable { - /** Value for infinite TTL of message */ - public static final int INFINITE_TTL = -1; - private DTNHost from; - private DTNHost to; - /** Identifier of the message */ - private String id; - /** Size of the message (bytes) */ - private int size; - /** List of nodes this message has passed */ - private List path; - /** Next unique identifier to be given */ - private static int nextUniqueId; - /** Unique ID of this message */ - private int uniqueId; - /** The time this message was received */ - private double timeReceived; - /** The time when this message was created */ - private double timeCreated; - /** Initial TTL of the message */ - private int initTtl; - - /** if a response to this message is required, this is the size of the - * response message (or 0 if no response is requested) */ - private int responseSize; - /** if this message is a response message, this is set to the request msg*/ + +/** + * A message that is created at a node or passed between nodes. + */ +public class Message implements Comparable { + /** Value for infinite TTL of message */ + public static final int INFINITE_TTL = -1; + private DTNHost from; + private DTNHost to; + /** Identifier of the message */ + private String id; + /** Size of the message (bytes) */ + private int size; + /** List of nodes this message has passed */ + private List path; + /** Next unique identifier to be given */ + private static int nextUniqueId; + /** Unique ID of this message */ + private int uniqueId; + /** The time this message was received */ + private double timeReceived; + /** The time when this message was created */ + private double timeCreated; + /** Initial TTL of the message */ + private int initTtl; + + /** if a response to this message is required, this is the size of the + * response message (or 0 if no response is requested) */ + private int responseSize; + /** if this message is a response message, this is set to the request msg*/ private Message requestMsg; - + /** Container for generic message properties. Note that all values * stored in the properties should be immutable because only a shallow * copy of the properties is made when replicating messages */ - private Map properties; - + private Map properties; + /** Application ID of the application that created the message */ private String appID; - - static { + + static { reset(); - DTNSim.registerForReset(Message.class.getCanonicalName()); - } - - /** - * Creates a new Message. - * @param from Who the message is (originally) from - * @param to Who the message is (originally) to - * @param id Message identifier (must be unique for message but - * will be the same for all replicates of the message) - * @param size Size of the message (in bytes) - */ - public Message(DTNHost from, DTNHost to, String id, int size) { - this.from = from; - this.to = to; - this.id = id; - this.size = size; - this.path = new ArrayList(); - this.uniqueId = nextUniqueId; - - this.timeCreated = SimClock.getTime(); - this.timeReceived = this.timeCreated; - this.initTtl = INFINITE_TTL; - this.responseSize = 0; - this.requestMsg = null; + DTNSim.registerForReset(Message.class.getCanonicalName()); + } + + /** + * Creates a new Message. + * @param from Who the message is (originally) from + * @param to Who the message is (originally) to + * @param id Message identifier (must be unique for message but + * will be the same for all replicates of the message) + * @param size Size of the message (in bytes) + */ + public Message(DTNHost from, DTNHost to, String id, int size) { + this.from = from; + this.to = to; + this.id = id; + this.size = size; + this.path = new ArrayList(); + this.uniqueId = nextUniqueId; + + this.timeCreated = SimClock.getTime(); + this.timeReceived = this.timeCreated; + this.initTtl = INFINITE_TTL; + this.responseSize = 0; + this.requestMsg = null; this.properties = null; this.appID = null; - - Message.nextUniqueId++; - addNodeOnPath(from); - } - - /** - * Returns the node this message is originally from - * @return the node this message is originally from - */ - public DTNHost getFrom() { - return this.from; - } - - /** - * Returns the node this message is originally to - * @return the node this message is originally to - */ - public DTNHost getTo() { - return this.to; - } - - /** - * Returns the ID of the message - * @return The message id - */ - public String getId() { - return this.id; - } - - /** - * Returns an ID that is unique per message instance - * (different for replicates too) - * @return The unique id - */ - public int getUniqueId() { - return this.uniqueId; - } - - /** - * Returns the size of the message (in bytes) - * @return the size of the message - */ - public int getSize() { - return this.size; - } - - /** - * Adds a new node on the list of nodes this message has passed - * @param node The node to add - */ - public void addNodeOnPath(DTNHost node) { - this.path.add(node); - } - - /** - * Returns a list of nodes this message has passed so far - * @return The list as vector - */ - public List getHops() { - return this.path; - } - - /** - * Returns the amount of hops this message has passed - * @return the amount of hops this message has passed - */ - public int getHopCount() { - return this.path.size() -1; - } - - /** - * Returns the time to live (minutes) of the message or Integer.MAX_VALUE - * if the TTL is infinite. Returned value can be negative if the TTL has - * passed already. - * @return The TTL (minutes) - */ - public int getTtl() { - if (this.initTtl == INFINITE_TTL) { - return Integer.MAX_VALUE; - } - else { - return (int)( ((this.initTtl * 60) - - (SimClock.getTime()-this.timeCreated)) /60.0 ); - } - } - - + + Message.nextUniqueId++; + addNodeOnPath(from); + } + + /** + * Returns the node this message is originally from + * @return the node this message is originally from + */ + public DTNHost getFrom() { + return this.from; + } + + /** + * Returns the node this message is originally to + * @return the node this message is originally to + */ + public DTNHost getTo() { + return this.to; + } + + /** + * Returns the ID of the message + * @return The message id + */ + public String getId() { + return this.id; + } + + /** + * Returns an ID that is unique per message instance + * (different for replicates too) + * @return The unique id + */ + public int getUniqueId() { + return this.uniqueId; + } + + /** + * Returns the size of the message (in bytes) + * @return the size of the message + */ + public int getSize() { + return this.size; + } + + /** + * Adds a new node on the list of nodes this message has passed + * @param node The node to add + */ + public void addNodeOnPath(DTNHost node) { + this.path.add(node); + } + + /** + * Returns a list of nodes this message has passed so far + * @return The list as vector + */ + public List getHops() { + return this.path; + } + + /** + * Returns the amount of hops this message has passed + * @return the amount of hops this message has passed + */ + public int getHopCount() { + return this.path.size() -1; + } + + /** + * Returns the time to live (minutes) of the message or Integer.MAX_VALUE + * if the TTL is infinite. Returned value can be negative if the TTL has + * passed already. + * @return The TTL (minutes) + */ + public int getTtl() { + if (this.initTtl == INFINITE_TTL) { + return Integer.MAX_VALUE; + } + else { + return (int)( ((this.initTtl * 60) - + (SimClock.getTime()-this.timeCreated)) /60.0 ); + } + } + + /** * Sets the initial TTL (time-to-live) for this message. The initial * TTL is the TTL when the original message was created. The current TTL - * is calculated based on the time of + * is calculated based on the time of * @param ttl The time-to-live to set */ public void setTtl(int ttl) { this.initTtl = ttl; } - - /** - * Sets the time when this message was received. - * @param time The time to set - */ - public void setReceiveTime(double time) { - this.timeReceived = time; - } - - /** - * Returns the time when this message was received - * @return The time - */ - public double getReceiveTime() { - return this.timeReceived; - } - - /** - * Returns the time when this message was created - * @return the time when this message was created - */ - public double getCreationTime() { - return this.timeCreated; - } - - /** - * If this message is a response to a request, sets the request message - * @param request The request message - */ - public void setRequest(Message request) { - this.requestMsg = request; - } - - /** - * Returns the message this message is response to or null if this is not - * a response message - * @return the message this message is response to - */ - public Message getRequest() { - return this.requestMsg; - } - - /** - * Returns true if this message is a response message - * @return true if this message is a response message - */ - public boolean isResponse() { - return this.requestMsg != null; - } - - /** - * Sets the requested response message's size. If size == 0, no response - * is requested (default) - * @param size Size of the response message - */ - public void setResponseSize(int size) { - this.responseSize = size; - } - - /** - * Returns the size of the requested response message or 0 if no response - * is requested. - * @return the size of the requested response message - */ - public int getResponseSize() { - return responseSize; - } - - /** - * Returns a string representation of the message - * @return a string representation of the message - */ - public String toString () { - return id; - } - - /** - * Deep copies message data from other message. If new fields are - * introduced to this class, most likely they should be copied here too - * (unless done in constructor). - * @param m The message where the data is copied - */ - protected void copyFrom(Message m) { - this.path = new ArrayList(m.path); - this.timeCreated = m.timeCreated; - this.responseSize = m.responseSize; + + /** + * Sets the time when this message was received. + * @param time The time to set + */ + public void setReceiveTime(double time) { + this.timeReceived = time; + } + + /** + * Returns the time when this message was received + * @return The time + */ + public double getReceiveTime() { + return this.timeReceived; + } + + /** + * Returns the time when this message was created + * @return the time when this message was created + */ + public double getCreationTime() { + return this.timeCreated; + } + + /** + * If this message is a response to a request, sets the request message + * @param request The request message + */ + public void setRequest(Message request) { + this.requestMsg = request; + } + + /** + * Returns the message this message is response to or null if this is not + * a response message + * @return the message this message is response to + */ + public Message getRequest() { + return this.requestMsg; + } + + /** + * Returns true if this message is a response message + * @return true if this message is a response message + */ + public boolean isResponse() { + return this.requestMsg != null; + } + + /** + * Sets the requested response message's size. If size == 0, no response + * is requested (default) + * @param size Size of the response message + */ + public void setResponseSize(int size) { + this.responseSize = size; + } + + /** + * Returns the size of the requested response message or 0 if no response + * is requested. + * @return the size of the requested response message + */ + public int getResponseSize() { + return responseSize; + } + + /** + * Returns a string representation of the message + * @return a string representation of the message + */ + public String toString () { + return id; + } + + /** + * Deep copies message data from other message. If new fields are + * introduced to this class, most likely they should be copied here too + * (unless done in constructor). + * @param m The message where the data is copied + */ + protected void copyFrom(Message m) { + this.path = new ArrayList(m.path); + this.timeCreated = m.timeCreated; + this.responseSize = m.responseSize; this.requestMsg = m.requestMsg; this.initTtl = m.initTtl; this.appID = m.appID; - + if (m.properties != null) { Set keys = m.properties.keySet(); for (String key : keys) { @@ -270,13 +270,13 @@ protected void copyFrom(Message m) { } } } - + /** - * Adds a generic property for this message. The key can be any string but + * Adds a generic property for this message. The key can be any string but * it should be such that no other class accidently uses the same value. * The value can be any object but it's good idea to store only immutable * objects because when message is replicated, only a shallow copy of the - * properties is made. + * properties is made. * @param key The key which is used to lookup the value * @param value The value to store * @throws SimError if the message already has a value for the given key @@ -284,13 +284,13 @@ protected void copyFrom(Message m) { public void addProperty(String key, Object value) throws SimError { if (this.properties != null && this.properties.containsKey(key)) { /* check to prevent accidental name space collisions */ - throw new SimError("Message " + this + " already contains value " + + throw new SimError("Message " + this + " already contains value " + "for a key " + key); } - + this.updateProperty(key, value); } - + /** * Returns an object that was stored to this message using the given * key. If such object is not found, null is returned. @@ -303,9 +303,9 @@ public Object getProperty(String key) { } return this.properties.get(key); } - + /** - * Updates a value for an existing property. For storing the value first + * Updates a value for an existing property. For storing the value first * time, {@link #addProperty(String, Object)} should be used which * checks for name space clashes. * @param key The key which is used to lookup the value @@ -316,34 +316,34 @@ public void updateProperty(String key, Object value) throws SimError { /* lazy creation to prevent performance overhead for classes that don't use the property feature */ this.properties = new HashMap(); - } + } this.properties.put(key, value); - } - - /** - * Returns a replicate of this message (identical except for the unique id) - * @return A replicate of the message - */ - public Message replicate() { - Message m = new Message(from, to, id, size); - m.copyFrom(this); - return m; - } - - /** - * Compares two messages by their ID (alphabetically). - * @see String#compareTo(String) - */ - public int compareTo(Message m) { - return toString().compareTo(m.toString()); - } - - /** - * Resets all static fields to default values - */ - public static void reset() { - nextUniqueId = 0; + } + + /** + * Returns a replicate of this message (identical except for the unique id) + * @return A replicate of the message + */ + public Message replicate() { + Message m = new Message(from, to, id, size); + m.copyFrom(this); + return m; + } + + /** + * Compares two messages by their ID (alphabetically). + * @see String#compareTo(String) + */ + public int compareTo(Message m) { + return toString().compareTo(m.toString()); + } + + /** + * Resets all static fields to default values + */ + public static void reset() { + nextUniqueId = 0; } /** @@ -358,6 +358,6 @@ public String getAppID() { */ public void setAppID(String appID) { this.appID = appID; - } - -} + } + +} diff --git a/core/MessageListener.java b/core/MessageListener.java index f4ee2048d..43e651d1b 100644 --- a/core/MessageListener.java +++ b/core/MessageListener.java @@ -1,56 +1,56 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - -/** - * Interface for classes that want to be informed about messages - * between hosts - * - */ -public interface MessageListener { - - /** - * Method is called when a new message is created - * @param m Message that was created - */ - public void newMessage(Message m); - - /** - * Method is called when a message's transfer is started - * @param m The message that is going to be transferred - * @param from Node where the message is transferred from - * @param to Node where the message is transferred to - */ - public void messageTransferStarted(Message m, DTNHost from, DTNHost to); - - /** - * Method is called when a message is deleted - * @param m The message that was deleted - * @param where The host where the message was deleted - * @param dropped True if the message was dropped, false if removed - */ - public void messageDeleted(Message m, DTNHost where, boolean dropped); - - /** - * Method is called when a message's transfer was aborted before - * it finished - * @param m The message that was being transferred - * @param from Node where the message was being transferred from - * @param to Node where the message was being transferred to - */ - public void messageTransferAborted(Message m, DTNHost from, DTNHost to); - - /** - * Method is called when a message is successfully transferred from - * a node to another. - * @param m The message that was transferred - * @param from Node where the message was transferred from - * @param to Node where the message was transferred to - * @param firstDelivery Was the target node final destination of the message - * and received this message for the first time. - */ - public void messageTransferred(Message m, DTNHost from, DTNHost to, - boolean firstDelivery); -} +package core; + +/** + * Interface for classes that want to be informed about messages + * between hosts + * + */ +public interface MessageListener { + + /** + * Method is called when a new message is created + * @param m Message that was created + */ + public void newMessage(Message m); + + /** + * Method is called when a message's transfer is started + * @param m The message that is going to be transferred + * @param from Node where the message is transferred from + * @param to Node where the message is transferred to + */ + public void messageTransferStarted(Message m, DTNHost from, DTNHost to); + + /** + * Method is called when a message is deleted + * @param m The message that was deleted + * @param where The host where the message was deleted + * @param dropped True if the message was dropped, false if removed + */ + public void messageDeleted(Message m, DTNHost where, boolean dropped); + + /** + * Method is called when a message's transfer was aborted before + * it finished + * @param m The message that was being transferred + * @param from Node where the message was being transferred from + * @param to Node where the message was being transferred to + */ + public void messageTransferAborted(Message m, DTNHost from, DTNHost to); + + /** + * Method is called when a message is successfully transferred from + * a node to another. + * @param m The message that was transferred + * @param from Node where the message was transferred from + * @param to Node where the message was transferred to + * @param firstDelivery Was the target node final destination of the message + * and received this message for the first time. + */ + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery); +} diff --git a/core/ModuleCommunicationBus.java b/core/ModuleCommunicationBus.java index d15177e17..bb2f02759 100644 --- a/core/ModuleCommunicationBus.java +++ b/core/ModuleCommunicationBus.java @@ -1,19 +1,19 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; +package core; import java.util.ArrayList; import java.util.HashMap; import java.util.List; - -/** + +/** * Intermodule communication bus. Works as a blackboard where modules can * post data, subscribe to data changes and also poll for data values. * This is fairly similar to Message class' property interface, but these - * values are shared for a node instead of message. - */ + * values are shared for a node instead of message. + */ public class ModuleCommunicationBus { /** Initial capacity for the listener lists (instead of 10) */ private static int INIT_CAPACITY = 3; @@ -21,7 +21,7 @@ public class ModuleCommunicationBus { private HashMap values; /** Subscribed listeners (or null if none)*/ private HashMap> listeners; - + /** * Constructor. */ @@ -29,12 +29,12 @@ public ModuleCommunicationBus() { this.values = null; /* use lazy creation */ this.listeners = null; } - + /** - * Adds a new property for this node. The key can be any string but + * Adds a new property for this node. The key can be any string but * it should be such that no other class accidently uses the same value. * Note that, unless the value is immutable, it can be changed by any - * object that can call {@link #getProperty}. + * object that can call {@link #getProperty}. * @param key The key which is used to lookup the value * @param value The value to store * @throws SimError if there is already a value for the given key @@ -42,15 +42,15 @@ public ModuleCommunicationBus() { public void addProperty(String key, Object value) throws SimError { if (this.values != null && this.values.containsKey(key)) { /* check to prevent accidental name space collisions */ - throw new SimError("A value for the key " + key + + throw new SimError("A value for the key " + key + " already exists"); } - + this.updateProperty(key, value); } - + /** - * Returns an object that was stored using the given key. If such object + * Returns an object that was stored using the given key. If such object * is not found, null is returned. * @param key The key used to lookup the object * @return The stored object or null if it isn't found @@ -61,7 +61,7 @@ public Object getProperty(String key) { } return this.values.get(key); } - + /** * Returns true if the bus contains a value for the given key * @param key The key for which a value's existence is checked @@ -73,9 +73,9 @@ public boolean containsProperty(String key) { } return this.values.containsKey(key); } - + /** - * Updates a value for an existing property. For storing the value first + * Updates a value for an existing property. For storing the value first * time, {@link #addProperty(String, Object)} should be used which * checks for name space clashes. * @param key The key which is used to lookup the value @@ -86,14 +86,14 @@ public void updateProperty(String key, Object value) throws SimError { /* lazy creation to prevent performance overhead for classes that don't use the property feature */ this.values = new HashMap(); - } + } this.values.put(key, value); notifyListeners(key, value); } /** - * Changes the Double value with given key with the value delta + * Changes the Double value with given key with the value delta * @param key The key of variable to update * @param delta Value added to the old value * @return The new value @@ -114,7 +114,7 @@ public double updateDouble(String key, double delta) throws SimError { return current + delta; } - + /** * Returns a double value from the communication bus. * @param key The key of the variable @@ -134,7 +134,7 @@ public double getDouble(String key, double naValue) throws SimError { throw new SimError("No Double value for key " + key); } } - + /** * Returns an integer value from the communication bus. * @param key The key of the variable @@ -154,7 +154,7 @@ public int getInt(String key, int naValue) throws SimError { throw new SimError("No Integer value for key " + key); } } - + /** * Subscribes a module to changes of a certain value. * @param key The key of the value whose changes the module is interested of @@ -163,20 +163,20 @@ public int getInt(String key, int naValue) throws SimError { public void subscribe(String key, ModuleCommunicationListener module) { if (this.listeners == null) { /* first listener for the whole node */ - this.listeners = + this.listeners = new HashMap>(); } - + List list = this.listeners.get(key); if (list == null) { /* first listener for this key */ list = new ArrayList(INIT_CAPACITY); this.listeners.put(key, list); } - + list.add(module); } - + /** * Removes a notification subscription * @param key The key for which the subscription should be removed @@ -184,46 +184,46 @@ public void subscribe(String key, ModuleCommunicationListener module) { */ public void unsubscribe(String key, ModuleCommunicationListener module) { List list; - + if (this.listeners == null) { return; /* no subscriptions */ } - + list = this.listeners.get(key); if (list == null) { return; /* no subscriptions for the key */ } - + list.remove(module); } - - + + /** - * Notifies all listeners that have subscribed to the given key + * Notifies all listeners that have subscribed to the given key * @param key The key which got new value * @param newValue The new value for the key */ private void notifyListeners(String key, Object newValue) { List list; - + if (this.listeners == null) { return; } list = this.listeners.get(key); - + if (list == null) { return; } - + for (ModuleCommunicationListener mcl : list) { mcl.moduleValueChanged(key, newValue); } } - - + + @Override public String toString() { - return "ComBus with mapping: " + (this.values != null ? + return "ComBus with mapping: " + (this.values != null ? this.values.toString() : "n/a"); } -} +} diff --git a/core/ModuleCommunicationListener.java b/core/ModuleCommunicationListener.java index 2df2c14b9..019d0f3cc 100644 --- a/core/ModuleCommunicationListener.java +++ b/core/ModuleCommunicationListener.java @@ -1,21 +1,21 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package core; - -/** - * This interface should be implemented by classes that want to be notified - * of variable value changes in ModuleCommunicationBuses. - */ -public interface ModuleCommunicationListener { - - /** - * This method is called whenever a variable, whose changes the module has - * registered to, changes. - * @param key The name of the variable - * @param newValue New value for the variable - */ - public void moduleValueChanged(String key, Object newValue); - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + * This interface should be implemented by classes that want to be notified + * of variable value changes in ModuleCommunicationBuses. + */ +public interface ModuleCommunicationListener { + + /** + * This method is called whenever a variable, whose changes the module has + * registered to, changes. + * @param key The name of the variable + * @param newValue New value for the variable + */ + public void moduleValueChanged(String key, Object newValue); + +} diff --git a/core/MovementListener.java b/core/MovementListener.java index 8b1bbd45c..6b2073779 100644 --- a/core/MovementListener.java +++ b/core/MovementListener.java @@ -1,29 +1,29 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - -/** - * Interface for classes that want to be informed about node movement. - */ -public interface MovementListener { - - /** - * Method is called every time a host receives a new destination from its - * movement model. - * @param host The host that got a new destination - * @param destination Coordinates of the destination - * @param speed Speed towards that destination - */ - public void newDestination(DTNHost host, Coord destination, double speed); - - /** - * Method is called when a host receives its initial location from - * movement model. - * @param host The host that got the location - * @param location Coordinates of the location - */ - public void initialLocation(DTNHost host, Coord location); - -} +package core; + +/** + * Interface for classes that want to be informed about node movement. + */ +public interface MovementListener { + + /** + * Method is called every time a host receives a new destination from its + * movement model. + * @param host The host that got a new destination + * @param destination Coordinates of the destination + * @param speed Speed towards that destination + */ + public void newDestination(DTNHost host, Coord destination, double speed); + + /** + * Method is called when a host receives its initial location from + * movement model. + * @param host The host that got the location + * @param location Coordinates of the location + */ + public void initialLocation(DTNHost host, Coord location); + +} diff --git a/core/NetworkInterface.java b/core/NetworkInterface.java index 24433d7e9..6d1581739 100644 --- a/core/NetworkInterface.java +++ b/core/NetworkInterface.java @@ -1,517 +1,517 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package core; - -import interfaces.ConnectivityGrid; -import interfaces.ConnectivityOptimizer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import routing.util.EnergyModel; - -import util.ActivenessHandler; - -/** - * Network interface of a DTNHost. Takes care of connectivity among hosts. - */ -abstract public class NetworkInterface implements ModuleCommunicationListener { - /** transmit range -setting id ({@value})*/ - public static final String TRANSMIT_RANGE_S = "transmitRange"; - /** transmit speed -setting id ({@value})*/ - public static final String TRANSMIT_SPEED_S = "transmitSpeed"; - /** scanning interval -setting id ({@value})*/ - public static final String SCAN_INTERVAL_S = "scanInterval"; - - /** - * Sub-namespace for the network related settings in the Group namespace - * ({@value}) - */ - public static final String NET_SUB_NS = "net"; - - /** Activeness offset jitter -setting id ({@value}) - * The maximum amount of random offset for the offset */ - public static final String ACT_JITTER_S = "activenessOffsetJitter"; - - /** {@link ModuleCommunicationBus} identifier for the "scanning interval" - variable. */ - public static final String SCAN_INTERVAL_ID = "Network.scanInterval"; - /** {@link ModuleCommunicationBus} identifier for the "radio range" - variable. Value type: double */ - public static final String RANGE_ID = "Network.radioRange"; - /** {@link ModuleCommunicationBus} identifier for the "transmission speed" - variable. Value type: integer */ - public static final String SPEED_ID = "Network.speed"; - - private static final int CON_UP = 1; - private static final int CON_DOWN = 2; - - private static Random rng; - protected DTNHost host = null; - - protected String interfacetype; - protected List connections; // connected hosts - private List cListeners = null; // list of listeners - private int address; // network interface address - protected double transmitRange; - protected double oldTransmitRange; - protected int transmitSpeed; - protected ConnectivityOptimizer optimizer = null; - /** scanning interval, or 0.0 if n/a */ - private double scanInterval; - private double lastScanTime; - - /** activeness handler for the node group */ - private ActivenessHandler ah; - /** maximum activeness jitter value for the node group */ - private int activenessJitterMax; - /** this interface's activeness jitter value */ - private int activenessJitterValue; - - static { - DTNSim.registerForReset(NetworkInterface.class.getCanonicalName()); - reset(); - } - - /** - * Resets the static fields of the class - */ - public static void reset() { - rng = new Random(0); - } - - /** - * For creating an empty class of a specific type - */ - public NetworkInterface(Settings s) { - this.interfacetype = s.getNameSpace(); - this.connections = new ArrayList(); - - this.transmitRange = s.getDouble(TRANSMIT_RANGE_S); - this.transmitSpeed = s.getInt(TRANSMIT_SPEED_S); - ensurePositiveValue(transmitRange, TRANSMIT_RANGE_S); - ensurePositiveValue(transmitSpeed, TRANSMIT_SPEED_S); - } - - /** - * For creating an empty class of a specific type - */ - public NetworkInterface() { - this.interfacetype = "Default"; - this.connections = new ArrayList(); - } - - /** - * copy constructor - */ - public NetworkInterface(NetworkInterface ni) { - this.connections = new ArrayList(); - this.host = ni.host; - this.cListeners = ni.cListeners; - this.interfacetype = ni.interfacetype; - this.transmitRange = ni.transmitRange; - this.transmitSpeed = ni.transmitSpeed; - this.scanInterval = ni.scanInterval; - this.ah = ni.ah; - - if (ni.activenessJitterMax > 0) { - this.activenessJitterValue = rng.nextInt(ni.activenessJitterMax); - } else { - this.activenessJitterValue = 0; - } - - this.scanInterval = ni.scanInterval; - /* draw lastScanTime of [0 -- scanInterval] */ - this.lastScanTime = rng.nextDouble() * this.scanInterval; - } - - /** - * Replication function - */ - abstract public NetworkInterface replicate(); - - /** - * For setting the host - needed when a prototype is copied for several - * hosts - * @param host The host where the network interface is - */ - public void setHost(DTNHost host) { - this.host = host; - ModuleCommunicationBus comBus = host.getComBus(); - - if (!comBus.containsProperty(SCAN_INTERVAL_ID) && - !comBus.containsProperty(RANGE_ID)) { - /* add properties and subscriptions only for the 1st interface */ - /* TODO: support for multiple interfaces */ - comBus.addProperty(SCAN_INTERVAL_ID, this.scanInterval); - comBus.addProperty(RANGE_ID, this.transmitRange); - comBus.addProperty(SPEED_ID, this.transmitSpeed); - comBus.subscribe(SCAN_INTERVAL_ID, this); - comBus.subscribe(RANGE_ID, this); - comBus.subscribe(SPEED_ID, this); - } - - if (transmitRange > 0) { - optimizer = ConnectivityGrid.ConnectivityGridFactory( - this.interfacetype.hashCode(), transmitRange); - optimizer.addInterface(this); - } else { - optimizer = null; - } - } - - /** - * Sets group-based settings for the network interface - * @param s The settings object using the right group namespace - */ - public void setGroupSettings(Settings s) { - s.setSubNameSpace(NET_SUB_NS); - ah = new ActivenessHandler(s); - - if (s.contains(SCAN_INTERVAL_S)) { - this.scanInterval = s.getDouble(SCAN_INTERVAL_S); - } else { - this.scanInterval = 0; - } - if (s.contains(ACT_JITTER_S)) { - this.activenessJitterMax = s.getInt(ACT_JITTER_S); - } - - s.restoreSubNameSpace(); - } - - /** - * For checking what interface type this interface is - */ - public String getInterfaceType() { - return interfacetype; - } - - /** - * For setting the connectionListeners - * @param cListeners List of connection listeners - */ - public void setClisteners(List cListeners) { - this.cListeners = cListeners; - } - - /** - * Returns the transmit range of this network layer - * @return the transmit range - */ - public double getTransmitRange() { - return this.transmitRange; - } - - /** - * Returns the transmit speed of this network layer with respect to the - * another network interface - * @param ni The other network interface - * @return the transmit speed - */ - public int getTransmitSpeed(NetworkInterface ni) { - return this.transmitSpeed; - } - - /** - * Returns a list of currently connected connections - * @return a list of currently connected connections - */ - public List getConnections() { - return this.connections; - } - - /** - * Returns true if the interface is on at the moment (false if not) - * @return true if the interface is on at the moment (false if not) - */ - public boolean isActive() { - boolean active; - - if (ah == null) { - return true; /* no handler: always active */ - } - - active = ah.isActive(this.activenessJitterValue); - - if (active && host.getComBus().getDouble(EnergyModel.ENERGY_VALUE_ID, - 1) <= 0) { - /* TODO: better way to check battery level */ - /* no battery -> inactive */ - active = false; - } - - if (active == false && this.transmitRange > 0) { - /* not active -> make range 0 */ - this.oldTransmitRange = this.transmitRange; - host.getComBus().updateProperty(RANGE_ID, 0.0); - } else if (active == true && this.transmitRange == 0.0) { - /* active, but range == 0 -> restore range */ - host.getComBus().updateProperty(RANGE_ID, - this.oldTransmitRange); - } - return active; - } - - /** - * Checks if this interface is currently in the scanning mode - * @return True if the interface is scanning; false if not - */ - public boolean isScanning() { - double simTime = SimClock.getTime(); - - if (!isActive()) { - return false; - } - - if (scanInterval > 0.0) { - if (simTime < lastScanTime) { - return false; /* not time for the first scan */ - } - else if (simTime > lastScanTime + scanInterval) { - lastScanTime = simTime; /* time to start the next scan round */ - return true; - } - else if (simTime != lastScanTime ){ - return false; /* not in the scan round */ - } - } - /* interval == 0 or still in the same scan round as when - last time asked */ - return true; - } - - /** - * Returns true if one of the connections of this interface is transferring - * data - * @return true if the interface transferring - */ - public boolean isTransferring() { - for (Connection c : this.connections) { - if (c.isTransferring()) { - return true; - } - } - return false; - } - - /** - * Connects the interface to another interface. - * - * Overload this in a derived class. Check the requirements for - * the connection to work in the derived class, then call - * connect(Connection, NetworkInterface) for the actual connection. - * @param anotherInterface The interface to connect to - */ - public abstract void connect(NetworkInterface anotherInterface); - - /** - * Connects this host to another host. The derived class should check - * that all pre-requisites for making a connection are satisfied before - * actually connecting. - * @param con The new connection object - * @param anotherInterface The interface to connect to - */ - protected void connect(Connection con, NetworkInterface anotherInterface) { - this.connections.add(con); - notifyConnectionListeners(CON_UP, anotherInterface.getHost()); - - // set up bidirectional connection - anotherInterface.getConnections().add(con); - - // inform routers about the connection - this.host.connectionUp(con); - anotherInterface.getHost().connectionUp(con); - } - - /** - * Disconnects this host from another host. The derived class should - * make the decision whether to disconnect or not - * @param con The connection to tear down - */ - protected void disconnect(Connection con, - NetworkInterface anotherInterface) { - con.setUpState(false); - notifyConnectionListeners(CON_DOWN, anotherInterface.getHost()); - - // tear down bidirectional connection - if (!anotherInterface.getConnections().remove(con)) { - throw new SimError("No connection " + con + " found in " + - anotherInterface); - } - - this.host.connectionDown(con); - anotherInterface.getHost().connectionDown(con); - } - - /** - * Returns true if another interface is within radio range of this interface - * and this interface is also within radio range of the another interface. - * @param anotherInterface The another interface - * @return True if the interface is within range, false if not - */ - protected boolean isWithinRange(NetworkInterface anotherInterface) { - double smallerRange = anotherInterface.getTransmitRange(); - double myRange = getTransmitRange(); - if (myRange < smallerRange) { - smallerRange = myRange; - } - - return this.host.getLocation().distance( - anotherInterface.getHost().getLocation()) <= smallerRange; - } - - /** - * Returns true if the given NetworkInterface is connected to this host. - * @param netinterface The other NetworkInterface to check - * @return True if the two hosts are connected - */ - protected boolean isConnected(NetworkInterface netinterface) { - for (int i = 0; i < this.connections.size(); i++) { - if (this.connections.get(i).getOtherInterface(this) == - netinterface) { - return true; - } - } - return false; - } - - /** - * Makes sure that a value is positive - * @param value Value to check - * @param settingName Name of the setting (for error's message) - * @throws SettingsError if the value was not positive - */ - protected void ensurePositiveValue(double value, String settingName) { - if (value < 0) { - throw new SettingsError("Negative value (" + value + - ") not accepted for setting " + settingName); - } - } - - /** - * Updates the state of current connections (ie tears down connections - * that are out of range, recalculates transmission speeds etc.). - */ - abstract public void update(); - - /** - * Notifies all the connection listeners about a change in connections. - * @param type Type of the change (e.g. {@link #CON_DOWN} ) - * @param otherHost The other host on the other end of the connection. - */ - private void notifyConnectionListeners(int type, DTNHost otherHost) { - if (this.cListeners == null) { - return; - } - for (ConnectionListener cl : this.cListeners) { - switch (type) { - case CON_UP: - cl.hostsConnected(this.host, otherHost); - break; - case CON_DOWN: - cl.hostsDisconnected(this.host, otherHost); - break; - default: - assert false : type; // invalid type code - } - } - } - - /** - * This method is called by the {@link ModuleCommunicationBus} when/if - * someone changes the scanning interval, transmit speed, or range - * @param key Identifier of the changed value - * @param newValue New value for the variable - */ - public void moduleValueChanged(String key, Object newValue) { - if (key.equals(SCAN_INTERVAL_ID)) { - this.scanInterval = (Double)newValue; - } - else if (key.equals(SPEED_ID)) { - this.transmitSpeed = (Integer)newValue; - } - else if (key.equals(RANGE_ID)) { - this.transmitRange = (Double)newValue; - } - else { - throw new SimError("Unexpected combus ID " + key); - } - } - - /** - * Creates a connection to another host. This method does not do any checks - * on whether the other node is in range or active - * (cf. {@link #connect(NetworkInterface)}). - * @param anotherInterface The interface to create the connection to - */ - public abstract void createConnection(NetworkInterface anotherInterface); - - /** - * Disconnect a connection between this and another host. - * @param anotherInterface The other host's network interface to disconnect - * from this host - */ - public void destroyConnection(NetworkInterface anotherInterface) { - DTNHost anotherHost = anotherInterface.getHost(); - for (int i=0; i < this.connections.size(); i++) { - if (this.connections.get(i).getOtherNode(this.host) == anotherHost){ - removeConnectionByIndex(i, anotherInterface); - } - } - // the connection didn't exist, do nothing - } - - /** - * Removes a connection by its position (index) in the connections array - * of the interface - * @param index The array index of the connection to be removed - * @param anotherInterface The interface of the other host - */ - private void removeConnectionByIndex(int index, - NetworkInterface anotherInterface) { - Connection con = this.connections.get(index); - DTNHost anotherNode = anotherInterface.getHost(); - con.setUpState(false); - notifyConnectionListeners(CON_DOWN, anotherNode); - - // tear down bidirectional connection - if (!anotherInterface.getConnections().remove(con)) { - throw new SimError("No connection " + con + " found in " + - anotherNode); - } - - this.host.connectionDown(con); - anotherNode.connectionDown(con); - - connections.remove(index); - } - - /** - * Returns the DTNHost of this interface - */ - public DTNHost getHost() { - return host; - } - - /** - * Returns the current location of the host of this interface. - * @return The location - */ - public Coord getLocation() { - return host.getLocation(); - } - - /** - * Returns a string representation of the object. - * @return a string representation of the object. - */ - public String toString() { - return this.address + " of " + this.host + - ". Connections: " + this.connections; - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import interfaces.ConnectivityGrid; +import interfaces.ConnectivityOptimizer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import routing.util.EnergyModel; + +import util.ActivenessHandler; + +/** + * Network interface of a DTNHost. Takes care of connectivity among hosts. + */ +abstract public class NetworkInterface implements ModuleCommunicationListener { + /** transmit range -setting id ({@value})*/ + public static final String TRANSMIT_RANGE_S = "transmitRange"; + /** transmit speed -setting id ({@value})*/ + public static final String TRANSMIT_SPEED_S = "transmitSpeed"; + /** scanning interval -setting id ({@value})*/ + public static final String SCAN_INTERVAL_S = "scanInterval"; + + /** + * Sub-namespace for the network related settings in the Group namespace + * ({@value}) + */ + public static final String NET_SUB_NS = "net"; + + /** Activeness offset jitter -setting id ({@value}) + * The maximum amount of random offset for the offset */ + public static final String ACT_JITTER_S = "activenessOffsetJitter"; + + /** {@link ModuleCommunicationBus} identifier for the "scanning interval" + variable. */ + public static final String SCAN_INTERVAL_ID = "Network.scanInterval"; + /** {@link ModuleCommunicationBus} identifier for the "radio range" + variable. Value type: double */ + public static final String RANGE_ID = "Network.radioRange"; + /** {@link ModuleCommunicationBus} identifier for the "transmission speed" + variable. Value type: integer */ + public static final String SPEED_ID = "Network.speed"; + + private static final int CON_UP = 1; + private static final int CON_DOWN = 2; + + private static Random rng; + protected DTNHost host = null; + + protected String interfacetype; + protected List connections; // connected hosts + private List cListeners = null; // list of listeners + private int address; // network interface address + protected double transmitRange; + protected double oldTransmitRange; + protected int transmitSpeed; + protected ConnectivityOptimizer optimizer = null; + /** scanning interval, or 0.0 if n/a */ + private double scanInterval; + private double lastScanTime; + + /** activeness handler for the node group */ + private ActivenessHandler ah; + /** maximum activeness jitter value for the node group */ + private int activenessJitterMax; + /** this interface's activeness jitter value */ + private int activenessJitterValue; + + static { + DTNSim.registerForReset(NetworkInterface.class.getCanonicalName()); + reset(); + } + + /** + * Resets the static fields of the class + */ + public static void reset() { + rng = new Random(0); + } + + /** + * For creating an empty class of a specific type + */ + public NetworkInterface(Settings s) { + this.interfacetype = s.getNameSpace(); + this.connections = new ArrayList(); + + this.transmitRange = s.getDouble(TRANSMIT_RANGE_S); + this.transmitSpeed = s.getInt(TRANSMIT_SPEED_S); + ensurePositiveValue(transmitRange, TRANSMIT_RANGE_S); + ensurePositiveValue(transmitSpeed, TRANSMIT_SPEED_S); + } + + /** + * For creating an empty class of a specific type + */ + public NetworkInterface() { + this.interfacetype = "Default"; + this.connections = new ArrayList(); + } + + /** + * copy constructor + */ + public NetworkInterface(NetworkInterface ni) { + this.connections = new ArrayList(); + this.host = ni.host; + this.cListeners = ni.cListeners; + this.interfacetype = ni.interfacetype; + this.transmitRange = ni.transmitRange; + this.transmitSpeed = ni.transmitSpeed; + this.scanInterval = ni.scanInterval; + this.ah = ni.ah; + + if (ni.activenessJitterMax > 0) { + this.activenessJitterValue = rng.nextInt(ni.activenessJitterMax); + } else { + this.activenessJitterValue = 0; + } + + this.scanInterval = ni.scanInterval; + /* draw lastScanTime of [0 -- scanInterval] */ + this.lastScanTime = rng.nextDouble() * this.scanInterval; + } + + /** + * Replication function + */ + abstract public NetworkInterface replicate(); + + /** + * For setting the host - needed when a prototype is copied for several + * hosts + * @param host The host where the network interface is + */ + public void setHost(DTNHost host) { + this.host = host; + ModuleCommunicationBus comBus = host.getComBus(); + + if (!comBus.containsProperty(SCAN_INTERVAL_ID) && + !comBus.containsProperty(RANGE_ID)) { + /* add properties and subscriptions only for the 1st interface */ + /* TODO: support for multiple interfaces */ + comBus.addProperty(SCAN_INTERVAL_ID, this.scanInterval); + comBus.addProperty(RANGE_ID, this.transmitRange); + comBus.addProperty(SPEED_ID, this.transmitSpeed); + comBus.subscribe(SCAN_INTERVAL_ID, this); + comBus.subscribe(RANGE_ID, this); + comBus.subscribe(SPEED_ID, this); + } + + if (transmitRange > 0) { + optimizer = ConnectivityGrid.ConnectivityGridFactory( + this.interfacetype.hashCode(), transmitRange); + optimizer.addInterface(this); + } else { + optimizer = null; + } + } + + /** + * Sets group-based settings for the network interface + * @param s The settings object using the right group namespace + */ + public void setGroupSettings(Settings s) { + s.setSubNameSpace(NET_SUB_NS); + ah = new ActivenessHandler(s); + + if (s.contains(SCAN_INTERVAL_S)) { + this.scanInterval = s.getDouble(SCAN_INTERVAL_S); + } else { + this.scanInterval = 0; + } + if (s.contains(ACT_JITTER_S)) { + this.activenessJitterMax = s.getInt(ACT_JITTER_S); + } + + s.restoreSubNameSpace(); + } + + /** + * For checking what interface type this interface is + */ + public String getInterfaceType() { + return interfacetype; + } + + /** + * For setting the connectionListeners + * @param cListeners List of connection listeners + */ + public void setClisteners(List cListeners) { + this.cListeners = cListeners; + } + + /** + * Returns the transmit range of this network layer + * @return the transmit range + */ + public double getTransmitRange() { + return this.transmitRange; + } + + /** + * Returns the transmit speed of this network layer with respect to the + * another network interface + * @param ni The other network interface + * @return the transmit speed + */ + public int getTransmitSpeed(NetworkInterface ni) { + return this.transmitSpeed; + } + + /** + * Returns a list of currently connected connections + * @return a list of currently connected connections + */ + public List getConnections() { + return this.connections; + } + + /** + * Returns true if the interface is on at the moment (false if not) + * @return true if the interface is on at the moment (false if not) + */ + public boolean isActive() { + boolean active; + + if (ah == null) { + return true; /* no handler: always active */ + } + + active = ah.isActive(this.activenessJitterValue); + + if (active && host.getComBus().getDouble(EnergyModel.ENERGY_VALUE_ID, + 1) <= 0) { + /* TODO: better way to check battery level */ + /* no battery -> inactive */ + active = false; + } + + if (active == false && this.transmitRange > 0) { + /* not active -> make range 0 */ + this.oldTransmitRange = this.transmitRange; + host.getComBus().updateProperty(RANGE_ID, 0.0); + } else if (active == true && this.transmitRange == 0.0) { + /* active, but range == 0 -> restore range */ + host.getComBus().updateProperty(RANGE_ID, + this.oldTransmitRange); + } + return active; + } + + /** + * Checks if this interface is currently in the scanning mode + * @return True if the interface is scanning; false if not + */ + public boolean isScanning() { + double simTime = SimClock.getTime(); + + if (!isActive()) { + return false; + } + + if (scanInterval > 0.0) { + if (simTime < lastScanTime) { + return false; /* not time for the first scan */ + } + else if (simTime > lastScanTime + scanInterval) { + lastScanTime = simTime; /* time to start the next scan round */ + return true; + } + else if (simTime != lastScanTime ){ + return false; /* not in the scan round */ + } + } + /* interval == 0 or still in the same scan round as when + last time asked */ + return true; + } + + /** + * Returns true if one of the connections of this interface is transferring + * data + * @return true if the interface transferring + */ + public boolean isTransferring() { + for (Connection c : this.connections) { + if (c.isTransferring()) { + return true; + } + } + return false; + } + + /** + * Connects the interface to another interface. + * + * Overload this in a derived class. Check the requirements for + * the connection to work in the derived class, then call + * connect(Connection, NetworkInterface) for the actual connection. + * @param anotherInterface The interface to connect to + */ + public abstract void connect(NetworkInterface anotherInterface); + + /** + * Connects this host to another host. The derived class should check + * that all pre-requisites for making a connection are satisfied before + * actually connecting. + * @param con The new connection object + * @param anotherInterface The interface to connect to + */ + protected void connect(Connection con, NetworkInterface anotherInterface) { + this.connections.add(con); + notifyConnectionListeners(CON_UP, anotherInterface.getHost()); + + // set up bidirectional connection + anotherInterface.getConnections().add(con); + + // inform routers about the connection + this.host.connectionUp(con); + anotherInterface.getHost().connectionUp(con); + } + + /** + * Disconnects this host from another host. The derived class should + * make the decision whether to disconnect or not + * @param con The connection to tear down + */ + protected void disconnect(Connection con, + NetworkInterface anotherInterface) { + con.setUpState(false); + notifyConnectionListeners(CON_DOWN, anotherInterface.getHost()); + + // tear down bidirectional connection + if (!anotherInterface.getConnections().remove(con)) { + throw new SimError("No connection " + con + " found in " + + anotherInterface); + } + + this.host.connectionDown(con); + anotherInterface.getHost().connectionDown(con); + } + + /** + * Returns true if another interface is within radio range of this interface + * and this interface is also within radio range of the another interface. + * @param anotherInterface The another interface + * @return True if the interface is within range, false if not + */ + protected boolean isWithinRange(NetworkInterface anotherInterface) { + double smallerRange = anotherInterface.getTransmitRange(); + double myRange = getTransmitRange(); + if (myRange < smallerRange) { + smallerRange = myRange; + } + + return this.host.getLocation().distance( + anotherInterface.getHost().getLocation()) <= smallerRange; + } + + /** + * Returns true if the given NetworkInterface is connected to this host. + * @param netinterface The other NetworkInterface to check + * @return True if the two hosts are connected + */ + protected boolean isConnected(NetworkInterface netinterface) { + for (int i = 0; i < this.connections.size(); i++) { + if (this.connections.get(i).getOtherInterface(this) == + netinterface) { + return true; + } + } + return false; + } + + /** + * Makes sure that a value is positive + * @param value Value to check + * @param settingName Name of the setting (for error's message) + * @throws SettingsError if the value was not positive + */ + protected void ensurePositiveValue(double value, String settingName) { + if (value < 0) { + throw new SettingsError("Negative value (" + value + + ") not accepted for setting " + settingName); + } + } + + /** + * Updates the state of current connections (ie tears down connections + * that are out of range, recalculates transmission speeds etc.). + */ + abstract public void update(); + + /** + * Notifies all the connection listeners about a change in connections. + * @param type Type of the change (e.g. {@link #CON_DOWN} ) + * @param otherHost The other host on the other end of the connection. + */ + private void notifyConnectionListeners(int type, DTNHost otherHost) { + if (this.cListeners == null) { + return; + } + for (ConnectionListener cl : this.cListeners) { + switch (type) { + case CON_UP: + cl.hostsConnected(this.host, otherHost); + break; + case CON_DOWN: + cl.hostsDisconnected(this.host, otherHost); + break; + default: + assert false : type; // invalid type code + } + } + } + + /** + * This method is called by the {@link ModuleCommunicationBus} when/if + * someone changes the scanning interval, transmit speed, or range + * @param key Identifier of the changed value + * @param newValue New value for the variable + */ + public void moduleValueChanged(String key, Object newValue) { + if (key.equals(SCAN_INTERVAL_ID)) { + this.scanInterval = (Double)newValue; + } + else if (key.equals(SPEED_ID)) { + this.transmitSpeed = (Integer)newValue; + } + else if (key.equals(RANGE_ID)) { + this.transmitRange = (Double)newValue; + } + else { + throw new SimError("Unexpected combus ID " + key); + } + } + + /** + * Creates a connection to another host. This method does not do any checks + * on whether the other node is in range or active + * (cf. {@link #connect(NetworkInterface)}). + * @param anotherInterface The interface to create the connection to + */ + public abstract void createConnection(NetworkInterface anotherInterface); + + /** + * Disconnect a connection between this and another host. + * @param anotherInterface The other host's network interface to disconnect + * from this host + */ + public void destroyConnection(NetworkInterface anotherInterface) { + DTNHost anotherHost = anotherInterface.getHost(); + for (int i=0; i < this.connections.size(); i++) { + if (this.connections.get(i).getOtherNode(this.host) == anotherHost){ + removeConnectionByIndex(i, anotherInterface); + } + } + // the connection didn't exist, do nothing + } + + /** + * Removes a connection by its position (index) in the connections array + * of the interface + * @param index The array index of the connection to be removed + * @param anotherInterface The interface of the other host + */ + private void removeConnectionByIndex(int index, + NetworkInterface anotherInterface) { + Connection con = this.connections.get(index); + DTNHost anotherNode = anotherInterface.getHost(); + con.setUpState(false); + notifyConnectionListeners(CON_DOWN, anotherNode); + + // tear down bidirectional connection + if (!anotherInterface.getConnections().remove(con)) { + throw new SimError("No connection " + con + " found in " + + anotherNode); + } + + this.host.connectionDown(con); + anotherNode.connectionDown(con); + + connections.remove(index); + } + + /** + * Returns the DTNHost of this interface + */ + public DTNHost getHost() { + return host; + } + + /** + * Returns the current location of the host of this interface. + * @return The location + */ + public Coord getLocation() { + return host.getLocation(); + } + + /** + * Returns a string representation of the object. + * @return a string representation of the object. + */ + public String toString() { + return this.address + " of " + this.host + + ". Connections: " + this.connections; + } + +} diff --git a/core/Settings.java b/core/Settings.java index f39794f52..302642fad 100644 --- a/core/Settings.java +++ b/core/Settings.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - +package core; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -19,112 +19,112 @@ import java.util.Stack; import util.Range; - -/** - * Interface for simulation settings stored in setting file(s). Settings - * class should be initialized before using (with {@link #init(String)}). If - * Settings isn't initialized, only settings in {@link #DEF_SETTINGS_FILE} - * are read. Normally, after initialization, settings in the given file can - * override any settings defined in the default settings file and/or define - * new settings. - *

All settings are key-value pairs. For parsing details see - * {@link java.util.Properties#getProperty(String)}. Value can be a single - * value or comma separated list of values. With CSV values, CSV methods - * must be used (e.g. {@link #getCsvInts(String, int)}). Setting value should - * not start and end with a bracket since those are reserved for run-specific - * values (see {@link #setRunIndex(int)}). In file paths directory separator - * should always be forward slash ("/"). - *

- */ -public class Settings { - /** properties object where the setting files are read into */ - protected static Properties props; - /** file name of the default settings file ({@value}) */ + +/** + * Interface for simulation settings stored in setting file(s). Settings + * class should be initialized before using (with {@link #init(String)}). If + * Settings isn't initialized, only settings in {@link #DEF_SETTINGS_FILE} + * are read. Normally, after initialization, settings in the given file can + * override any settings defined in the default settings file and/or define + * new settings. + *

All settings are key-value pairs. For parsing details see + * {@link java.util.Properties#getProperty(String)}. Value can be a single + * value or comma separated list of values. With CSV values, CSV methods + * must be used (e.g. {@link #getCsvInts(String, int)}). Setting value should + * not start and end with a bracket since those are reserved for run-specific + * values (see {@link #setRunIndex(int)}). In file paths directory separator + * should always be forward slash ("/"). + *

+ */ +public class Settings { + /** properties object where the setting files are read into */ + protected static Properties props; + /** file name of the default settings file ({@value}) */ public static final String DEF_SETTINGS_FILE ="default_settings.txt"; - - /** + + /** * Setting to define the file name where all read settings are written - * ({@value}. If set to an empty string, standard output is used. - * By default setting are not written anywhere. + * ({@value}. If set to an empty string, standard output is used. + * By default setting are not written anywhere. */ - public static final String SETTING_OUTPUT_S = "Settings.output"; - - /** delimiter for requested values in strings ({@value}) - * @see #valueFillString(String) */ + public static final String SETTING_OUTPUT_S = "Settings.output"; + + /** delimiter for requested values in strings ({@value}) + * @see #valueFillString(String) */ public static final String FILL_DELIMITER = "%%"; - + /** Stream where all read settings are written to */ private static PrintStream out = null; - private static Set writtenSettings = new HashSet(); - - /** run index for run-specific settings */ - private static int runIndex = 0; - private String namespace = null; // namespace to look the settings from - private String secondaryNamespace = null; - private Stack oldNamespaces; - private Stack secondaryNamespaces; - - /** - * Creates a setting object with a namespace. Namespace is the prefix - * of the all subsequent setting requests. - * @param namespace Namespace to use - */ - public Settings(String namespace) { - this.oldNamespaces = new Stack(); - this.secondaryNamespaces = new Stack(); - setNameSpace(namespace); - } - - /** - * Create a setting object without namespace. All setting requests must - * be prefixed with a valid namespace (e.g. "Report.nrofReports"). - */ - public Settings() { - this(null); - } - - /** - * Sets the run index for the settings (only has effect on settings with - * run array). A run array can be defined with syntax
- * [settingFor1stRun ; settingFor2ndRun ; SettingFor3rdRun] - *
I.e. settings are put in brackets and delimited with semicolon. - * First run's setting is returned when index is 0, second when index is - * 1 etc. If run index is bigger than run array's length, indexing wraps - * around in run array (i.e. return value is the value at index - * runIndex % arrayLength). - * To disable whole run-index-thing, set index to value smaller than - * zero (e.g. -1). When disabled, run-arrays are returned as normal values, - * including the brackets. - * @param index The run index to use for subsequent settings calls, or - * -1 to disable run indexing - */ - public static void setRunIndex(int index) { + private static Set writtenSettings = new HashSet(); + + /** run index for run-specific settings */ + private static int runIndex = 0; + private String namespace = null; // namespace to look the settings from + private String secondaryNamespace = null; + private Stack oldNamespaces; + private Stack secondaryNamespaces; + + /** + * Creates a setting object with a namespace. Namespace is the prefix + * of the all subsequent setting requests. + * @param namespace Namespace to use + */ + public Settings(String namespace) { + this.oldNamespaces = new Stack(); + this.secondaryNamespaces = new Stack(); + setNameSpace(namespace); + } + + /** + * Create a setting object without namespace. All setting requests must + * be prefixed with a valid namespace (e.g. "Report.nrofReports"). + */ + public Settings() { + this(null); + } + + /** + * Sets the run index for the settings (only has effect on settings with + * run array). A run array can be defined with syntax
+ * [settingFor1stRun ; settingFor2ndRun ; SettingFor3rdRun] + *
I.e. settings are put in brackets and delimited with semicolon. + * First run's setting is returned when index is 0, second when index is + * 1 etc. If run index is bigger than run array's length, indexing wraps + * around in run array (i.e. return value is the value at index + * runIndex % arrayLength). + * To disable whole run-index-thing, set index to value smaller than + * zero (e.g. -1). When disabled, run-arrays are returned as normal values, + * including the brackets. + * @param index The run index to use for subsequent settings calls, or + * -1 to disable run indexing + */ + public static void setRunIndex(int index) { runIndex = index; - writtenSettings.clear(); + writtenSettings.clear(); } - + /** - * Checks that the given integer array contains a valid range. I.e., - * the length of the array must be two and + * Checks that the given integer array contains a valid range. I.e., + * the length of the array must be two and * first_value <= second_value. * @param range The range array * @param sname Name of the setting (for error messages) * @throws SettingsError If the given array didn't qualify as a range */ - public void assertValidRange(int range[], String sname) + public void assertValidRange(int range[], String sname) throws SettingsError { if (range.length != 2) { - throw new SettingsError("Range setting " + - getFullPropertyName(sname) + + throw new SettingsError("Range setting " + + getFullPropertyName(sname) + " should contain only two comma separated integer values"); } if (range[0] > range[1]) { - throw new SettingsError("Range setting's " + - getFullPropertyName(sname) + + throw new SettingsError("Range setting's " + + getFullPropertyName(sname) + " first value should be smaller or equal to second value"); } - } - + } + /** * Makes sure that the given settings value is positive * @param value Value to check @@ -133,21 +133,21 @@ public void assertValidRange(int range[], String sname) */ public void ensurePositiveValue(double value, String settingName) { if (value < 0) { - throw new SettingsError("Negative value (" + value + + throw new SettingsError("Negative value (" + value + ") not accepted for setting " + settingName); } } - - /** - * Sets the namespace to something else than the current namespace. - * This change can be reverted using {@link #restoreNameSpace()} - * @param namespace The new namespace - */ - public void setNameSpace(String namespace) { - this.oldNamespaces.push(this.namespace); - this.namespace = namespace; + + /** + * Sets the namespace to something else than the current namespace. + * This change can be reverted using {@link #restoreNameSpace()} + * @param namespace The new namespace + */ + public void setNameSpace(String namespace) { + this.oldNamespaces.push(this.namespace); + this.namespace = namespace; } - + /** * Appends the given namespace to the the current namespace, * for both the primary and secondary namespace . @@ -161,108 +161,108 @@ public void setSubNameSpace(String namespace) { this.secondaryNamespaces.push(this.secondaryNamespace); this.secondaryNamespace = this.secondaryNamespace + "." + namespace; } - - /** - * Returns full (namespace prefixed) property name for a setting. - * @param setting The name of the setting - * @return The setting name prefixed with fully qualified name of the - * namespace where the requested setting would be retrieved from or null - * if that setting is not found from any of the current namespace(s) - */ - public String getFullPropertyName(String setting) { - if (!contains(setting)) { - return null; - } - - if (props.getProperty(getFullPropertyName(setting, false)) != null) { - return getFullPropertyName(setting, false); - } - - // not found from primary, but Settings contains -> must be from 2ndary - else return getFullPropertyName(setting, true); - } - - /** + + /** + * Returns full (namespace prefixed) property name for a setting. + * @param setting The name of the setting + * @return The setting name prefixed with fully qualified name of the + * namespace where the requested setting would be retrieved from or null + * if that setting is not found from any of the current namespace(s) + */ + public String getFullPropertyName(String setting) { + if (!contains(setting)) { + return null; + } + + if (props.getProperty(getFullPropertyName(setting, false)) != null) { + return getFullPropertyName(setting, false); + } + + // not found from primary, but Settings contains -> must be from 2ndary + else return getFullPropertyName(setting, true); + } + + /** * Returns the namespace of the settings object * @return the namespace of the settings object */ public String getNameSpace() { return this.namespace; } - - /** + + /** * Returns the secondary namespace of the settings object * @return the secondary namespace of the settings object */ public String getSecondaryNameSpace() { return this.secondaryNamespace; } - - /** - * Sets a secondary namespace where a setting is searched from if it - * isn't found from the primary namespace. Secondary namespace can - * be used e.g. as a "default" space where the settings are looked from - * if no specific setting is set. - * This change can be reverted using {@link #restoreSecondaryNamespace()} - * @param namespace The new secondary namespace or null if secondary - * namespace is not used (default behavior) - */ - public void setSecondaryNamespace(String namespace) { - this.secondaryNamespaces.push(this.secondaryNamespace); - this.secondaryNamespace = namespace; - } - - /** - * Restores the namespace that was in use before a call to setNameSpace - * @see #setNameSpace(String) - */ - public void restoreNameSpace() { - this.namespace = this.oldNamespaces.pop(); - } - - /** - * Restores the secondary namespace that was in use before a call to - * setSecondaryNameSpace - * @see #setSecondaryNamespace(String) - */ - public void restoreSecondaryNamespace() { - this.secondaryNamespace = this.secondaryNamespaces.pop(); - } - - /** - * Reverts the change made with {@link #setSubNameSpace(String)}, i.e., + + /** + * Sets a secondary namespace where a setting is searched from if it + * isn't found from the primary namespace. Secondary namespace can + * be used e.g. as a "default" space where the settings are looked from + * if no specific setting is set. + * This change can be reverted using {@link #restoreSecondaryNamespace()} + * @param namespace The new secondary namespace or null if secondary + * namespace is not used (default behavior) + */ + public void setSecondaryNamespace(String namespace) { + this.secondaryNamespaces.push(this.secondaryNamespace); + this.secondaryNamespace = namespace; + } + + /** + * Restores the namespace that was in use before a call to setNameSpace + * @see #setNameSpace(String) + */ + public void restoreNameSpace() { + this.namespace = this.oldNamespaces.pop(); + } + + /** + * Restores the secondary namespace that was in use before a call to + * setSecondaryNameSpace + * @see #setSecondaryNamespace(String) + */ + public void restoreSecondaryNamespace() { + this.secondaryNamespace = this.secondaryNamespaces.pop(); + } + + /** + * Reverts the change made with {@link #setSubNameSpace(String)}, i.e., * restores both the primary and secondary namespace. */ public void restoreSubNameSpace() { restoreNameSpace(); restoreSecondaryNamespace(); - } - - /** - * Initializes the settings all Settings objects will use. This should be - * called before any setting requests. Subsequent calls replace all - * old settings and then Settings contains only the new settings. - * The file {@link #DEF_SETTINGS_FILE}, if exists, is always read. - * @param propFile Path to the property file where additional settings - * are read from or null if no additional settings files are needed. - * @throws SettingsError If loading the settings file(s) didn't succeed - */ - public static void init(String propFile) throws SettingsError { + } + + /** + * Initializes the settings all Settings objects will use. This should be + * called before any setting requests. Subsequent calls replace all + * old settings and then Settings contains only the new settings. + * The file {@link #DEF_SETTINGS_FILE}, if exists, is always read. + * @param propFile Path to the property file where additional settings + * are read from or null if no additional settings files are needed. + * @throws SettingsError If loading the settings file(s) didn't succeed + */ + public static void init(String propFile) throws SettingsError { String outFile; - try { + try { if (new File(DEF_SETTINGS_FILE).exists()) { - Properties defProperties = new Properties(); - defProperties.load(new FileInputStream(DEF_SETTINGS_FILE)); + Properties defProperties = new Properties(); + defProperties.load(new FileInputStream(DEF_SETTINGS_FILE)); props = new Properties(defProperties); } else { props = new Properties(); - } - if (propFile != null) { - props.load(new FileInputStream(propFile)); - } - } catch (IOException e) { - throw new SettingsError(e); + } + if (propFile != null) { + props.load(new FileInputStream(propFile)); + } + } catch (IOException e) { + throw new SettingsError(e); } outFile = props.getProperty(SETTING_OUTPUT_S); @@ -278,8 +278,8 @@ public static void init(String propFile) throws SettingsError { } } } - } - + } + /** * Reads another settings file and adds the key-value pairs to the current * settings overriding any values that already existed with the same keys. @@ -294,7 +294,7 @@ public static void addSettings(String propFile) throws SettingsError { throw new SettingsError(e); } } - + /** * Writes the given setting string to the settings output (if any) * @param setting The string to write @@ -308,87 +308,87 @@ private static void outputSetting(String setting) { writtenSettings.add(setting); } } - - /** - * Returns true if a setting with defined name (in the current namespace - * or secondary namespace if such is set) exists and has some value - * (not just white space) - * @param name Name of the setting to check - * @return True if the setting exists, false if not - */ - public boolean contains(String name) { - try { - String value = getSetting(name); - if (value == null) { - return false; - } - - else return value.trim().length() > 0; - } - catch (SettingsError e) { - return false; // didn't find the setting - } - } - - /** - * Returns full (namespace prefixed) property name for setting. - * @param name Name of the settings - * @param secondary If true, the secondary namespace is used. - * @return full (prefixed with current namespace) property name for setting - */ - private String getFullPropertyName(String name, boolean secondary) { - String usedNamespace = (secondary ? secondaryNamespace : namespace); - - if (usedNamespace != null) { - return usedNamespace + "." + name; - } - else { - return name; - } - } - - /** - * Returns a String-valued setting. Setting is first looked from the - * namespace that is set (if any) and then from the secondary namespace - * (if any). All other getters use this method as their first step too - * (so all getters may throw SettingsError and look from both namespaces). - * @param name Name of the setting to get - * @return The contents of the setting in a String - * @throws SettingsError if the setting is not found from either one of - * the namespaces - */ + + /** + * Returns true if a setting with defined name (in the current namespace + * or secondary namespace if such is set) exists and has some value + * (not just white space) + * @param name Name of the setting to check + * @return True if the setting exists, false if not + */ + public boolean contains(String name) { + try { + String value = getSetting(name); + if (value == null) { + return false; + } + + else return value.trim().length() > 0; + } + catch (SettingsError e) { + return false; // didn't find the setting + } + } + + /** + * Returns full (namespace prefixed) property name for setting. + * @param name Name of the settings + * @param secondary If true, the secondary namespace is used. + * @return full (prefixed with current namespace) property name for setting + */ + private String getFullPropertyName(String name, boolean secondary) { + String usedNamespace = (secondary ? secondaryNamespace : namespace); + + if (usedNamespace != null) { + return usedNamespace + "." + name; + } + else { + return name; + } + } + + /** + * Returns a String-valued setting. Setting is first looked from the + * namespace that is set (if any) and then from the secondary namespace + * (if any). All other getters use this method as their first step too + * (so all getters may throw SettingsError and look from both namespaces). + * @param name Name of the setting to get + * @return The contents of the setting in a String + * @throws SettingsError if the setting is not found from either one of + * the namespaces + */ public String getSetting(String name) { - String fullPropName; - if (props == null) { - init(null); - } - fullPropName = getFullPropertyName(name, false); - String value = props.getProperty(fullPropName); - - if (value != null) { // found value, check if run setting can be parsed - value = parseRunSetting(value.trim()); - } - - if ((value == null || value.length() == 0) && - this.secondaryNamespace != null) { + String fullPropName; + if (props == null) { + init(null); + } + fullPropName = getFullPropertyName(name, false); + String value = props.getProperty(fullPropName); + + if (value != null) { // found value, check if run setting can be parsed + value = parseRunSetting(value.trim()); + } + + if ((value == null || value.length() == 0) && + this.secondaryNamespace != null) { // try secondary namespace if the value wasn't found from primary - fullPropName = getFullPropertyName(name, true); - value = props.getProperty(fullPropName); - - if (value != null) { - value = parseRunSetting(value.trim()); - } - } - + fullPropName = getFullPropertyName(name, true); + value = props.getProperty(fullPropName); + + if (value != null) { + value = parseRunSetting(value.trim()); + } + } + if (value == null || value.length() == 0) { - throw new SettingsError("Can't find setting " + + throw new SettingsError("Can't find setting " + getPropertyNamesString(name)); - } - - outputSetting(fullPropName + " = " + value); - return value; - } - + } + + outputSetting(fullPropName + " = " + value); + return value; + } + /** * Returns the given setting if it exists, or defaultValue if the setting * does not exist @@ -404,61 +404,61 @@ public String getSetting(String name, String defaultValue) { return getSetting(name); } } - - /** - * Parses run-specific settings from a String value - * @param value The String to parse - * @return The runIndex % arrayLength'th value of the run array - */ - private static String parseRunSetting(String value) { - final String RUN_ARRAY_START = "["; - final String RUN_ARRAY_END = "]"; - final String RUN_ARRAY_DELIM = ";"; - final int MIN_LENGTH = 3; // minimum run is one value. e.g. "[v]" - - if (!value.startsWith(RUN_ARRAY_START) || - !value.endsWith(RUN_ARRAY_END) || - runIndex < 0 || - value.length() < MIN_LENGTH) { - return value; // standard format setting -> return - } - - value = value.substring(1,value.length()-1); // remove brackets - String[] valueArr = value.split(RUN_ARRAY_DELIM); - int arrIndex = runIndex % valueArr.length; - value = valueArr[arrIndex].trim(); - - return value; - } - - /** - * Returns the setting name appended to namespace name(s) on a String - * (for error messages) - * @param name Name of the setting - * @return the setting name appended to namespace name(s) on a String - */ - private String getPropertyNamesString(String name) { - if (this.secondaryNamespace != null) { - return "'"+ this.secondaryNamespace + "." + name + "' nor '" + - this.namespace + "." + name + "'"; - } - else if (this.namespace != null){ - return "'" + this.namespace + "." + name + "'"; - } - else { - return "'" + name + "'"; - } - } - - /** - * Returns a double-valued setting - * @param name Name of the setting to get - * @return Value of the setting as a double - */ - public double getDouble(String name) { - return parseDouble(getSetting(name), name); - } - + + /** + * Parses run-specific settings from a String value + * @param value The String to parse + * @return The runIndex % arrayLength'th value of the run array + */ + private static String parseRunSetting(String value) { + final String RUN_ARRAY_START = "["; + final String RUN_ARRAY_END = "]"; + final String RUN_ARRAY_DELIM = ";"; + final int MIN_LENGTH = 3; // minimum run is one value. e.g. "[v]" + + if (!value.startsWith(RUN_ARRAY_START) || + !value.endsWith(RUN_ARRAY_END) || + runIndex < 0 || + value.length() < MIN_LENGTH) { + return value; // standard format setting -> return + } + + value = value.substring(1,value.length()-1); // remove brackets + String[] valueArr = value.split(RUN_ARRAY_DELIM); + int arrIndex = runIndex % valueArr.length; + value = valueArr[arrIndex].trim(); + + return value; + } + + /** + * Returns the setting name appended to namespace name(s) on a String + * (for error messages) + * @param name Name of the setting + * @return the setting name appended to namespace name(s) on a String + */ + private String getPropertyNamesString(String name) { + if (this.secondaryNamespace != null) { + return "'"+ this.secondaryNamespace + "." + name + "' nor '" + + this.namespace + "." + name + "'"; + } + else if (this.namespace != null){ + return "'" + this.namespace + "." + name + "'"; + } + else { + return "'" + name + "'"; + } + } + + /** + * Returns a double-valued setting + * @param name Name of the setting to get + * @return Value of the setting as a double + */ + public double getDouble(String name) { + return parseDouble(getSetting(name), name); + } + /** * Returns a double-valued setting, or the default value if the given * setting does not exist @@ -469,142 +469,142 @@ public double getDouble(String name) { public double getDouble(String name, double defaultValue) { return parseDouble(getSetting(name, ""+defaultValue), name); } - - /** - * Parses a double value from a String valued setting. Supports - * kilo (k), mega (M) and giga (G) suffixes. - * @param value String value to parse - * @param setting The setting where this value was from (for error msgs) - * @return The value as a double - * @throws SettingsError if the value wasn't a numeric value - * (or the suffix wasn't recognized) - */ - private double parseDouble(String value, String setting) { - double number; - int multiplier = 1; - - if (value.endsWith("k")) { - multiplier = 1000; - } - else if (value.endsWith("M")) { - multiplier = 1000000; - } - else if (value.endsWith("G")) { - multiplier = 1000000000; - } - - if (multiplier > 1) { // take the suffix away before parsing - value = value.substring(0,value.length()-1); - } - - try { - number = Double.parseDouble(value) * multiplier; - } catch (NumberFormatException e) { - throw new SettingsError("Invalid numeric setting '" + value + - "' for '" + setting +"'\n" + e.getMessage()); - } - return number; - } - - /** - * Returns a CSV setting. Value part of the setting must be a list of - * comma separated values. Whitespace between values is trimmed away. - * @param name Name of the setting - * @return Array of values that were comma-separated - * @throws SettingsError if something went wrong with reading - */ - public String[] getCsvSetting(String name) { - ArrayList values = new ArrayList(); - String csv = getSetting(name); - Scanner s = new Scanner(csv); - s.useDelimiter(","); - - while (s.hasNext()) { - values.add(s.next().trim()); - } - - return values.toArray(new String[0]); - } - - /** - * Returns a CSV setting containing expected amount of values. - * Value part of the setting must be a list of - * comma separated values. Whitespace between values is trimmed away. - * @param name Name of the setting - * @param expectedCount how many values are expected - * @return Array of values that were comma-separated - * @throws SettingsError if something went wrong with reading or didn't - * read the expected amount of values. - */ - public String[] getCsvSetting(String name, int expectedCount) { - String[] values = getCsvSetting(name); - - if (values.length != expectedCount) { - throw new SettingsError("Read unexpected amount (" + values.length + - ") of comma separated values for setting '" - + name + "' (expected " + expectedCount + ")"); - } - - return values; - } - - /** - * Returns an array of CSV setting double values containing expected - * amount of values. - * @param name Name of the setting - * @param expectedCount how many values are expected - * @return Array of values that were comma-separated - * @see #getCsvSetting(String, int) - */ - public double[] getCsvDoubles(String name, int expectedCount) { - return parseDoubles(getCsvSetting(name, expectedCount),name); - } - - /** - * Returns an array of CSV setting double values. - * @param name Name of the setting - * @return Array of values that were comma-separated - * @see #getCsvSetting(String) - */ - public double[] getCsvDoubles(String name) { - return parseDoubles(getCsvSetting(name), name); - } - - /** - * Parses a double array out of a String array - * @param strings The array of strings containing double values - * @param name Name of the setting - * @return Array of double values parsed from the string values - */ - private double[] parseDoubles(String[] strings, String name) { - double[] values = new double[strings.length]; - for (int i=0; i 1) { // take the suffix away before parsing + value = value.substring(0,value.length()-1); + } + + try { + number = Double.parseDouble(value) * multiplier; + } catch (NumberFormatException e) { + throw new SettingsError("Invalid numeric setting '" + value + + "' for '" + setting +"'\n" + e.getMessage()); + } + return number; + } + + /** + * Returns a CSV setting. Value part of the setting must be a list of + * comma separated values. Whitespace between values is trimmed away. + * @param name Name of the setting + * @return Array of values that were comma-separated + * @throws SettingsError if something went wrong with reading + */ + public String[] getCsvSetting(String name) { + ArrayList values = new ArrayList(); + String csv = getSetting(name); + Scanner s = new Scanner(csv); + s.useDelimiter(","); + + while (s.hasNext()) { + values.add(s.next().trim()); + } + + return values.toArray(new String[0]); + } + + /** + * Returns a CSV setting containing expected amount of values. + * Value part of the setting must be a list of + * comma separated values. Whitespace between values is trimmed away. + * @param name Name of the setting + * @param expectedCount how many values are expected + * @return Array of values that were comma-separated + * @throws SettingsError if something went wrong with reading or didn't + * read the expected amount of values. + */ + public String[] getCsvSetting(String name, int expectedCount) { + String[] values = getCsvSetting(name); + + if (values.length != expectedCount) { + throw new SettingsError("Read unexpected amount (" + values.length + + ") of comma separated values for setting '" + + name + "' (expected " + expectedCount + ")"); + } + + return values; + } + + /** + * Returns an array of CSV setting double values containing expected + * amount of values. + * @param name Name of the setting + * @param expectedCount how many values are expected + * @return Array of values that were comma-separated + * @see #getCsvSetting(String, int) + */ + public double[] getCsvDoubles(String name, int expectedCount) { + return parseDoubles(getCsvSetting(name, expectedCount),name); + } + + /** + * Returns an array of CSV setting double values. + * @param name Name of the setting + * @return Array of values that were comma-separated + * @see #getCsvSetting(String) + */ + public double[] getCsvDoubles(String name) { + return parseDoubles(getCsvSetting(name), name); + } + + /** + * Parses a double array out of a String array + * @param strings The array of strings containing double values + * @param name Name of the setting + * @return Array of double values parsed from the string values + */ + private double[] parseDoubles(String[] strings, String name) { + double[] values = new double[strings.length]; + for (int i=0; i[] argsClass = {Settings.class}; - Object[] args = {this}; - - return loadObject(className, argsClass, args); - } - - /** - * Creates (and dynamically loads the class of) an object using the - * constructor without any parameters. - * @param className Name of the class of the object - * @return Initialized object - * @throws SettingsError if object couldn't be created - */ - public Object createObject(String className) { - return loadObject(className, null, null); - } - - /** - * Dynamically loads and creates an object. - * @param className Name of the class of the object - * @param argsClass Class(es) of the argument(s) or null if no-argument - * constructor should be called - * @param args Argument(s) - * @return The new object - * @throws SettingsError if object couldn't be created - */ - private Object loadObject(String className, Class[] argsClass, - Object[] args) { - Object o = null; - Class objClass = getClass(className); - Constructor constructor; - - try { - if (argsClass != null) { // use a specific constructor - constructor = objClass.getConstructor((Class[])argsClass); - o = constructor.newInstance(args); - } - else { // call empty constructor - o = objClass.newInstance(); - } - } catch (SecurityException e) { - e.printStackTrace(); - throw new SettingsError("Fatal exception " + e, e); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - throw new SettingsError("Fatal exception " + e, e); - } catch (NoSuchMethodException e) { - throw new SettingsError("Class '" + className + - "' doesn't have a suitable constructor", e); - } catch (InstantiationException e) { - throw new SettingsError("Can't create an instance of '" + - className + "'", e); - } catch (IllegalAccessException e) { - e.printStackTrace(); - throw new SettingsError("Fatal exception " + e, e); - } catch (InvocationTargetException e) { - // this exception occurs if initialization of the object fails + } + + /** + * Creates (and dynamically loads the class of) an object that + * initializes itself using the settings in this Settings object + * (given as the only parameter to the constructor). + * @param className Name of the class of the object + * @return Initialized object + * @throws SettingsError if object couldn't be created + */ + public Object createIntializedObject(String className) { + Class[] argsClass = {Settings.class}; + Object[] args = {this}; + + return loadObject(className, argsClass, args); + } + + /** + * Creates (and dynamically loads the class of) an object using the + * constructor without any parameters. + * @param className Name of the class of the object + * @return Initialized object + * @throws SettingsError if object couldn't be created + */ + public Object createObject(String className) { + return loadObject(className, null, null); + } + + /** + * Dynamically loads and creates an object. + * @param className Name of the class of the object + * @param argsClass Class(es) of the argument(s) or null if no-argument + * constructor should be called + * @param args Argument(s) + * @return The new object + * @throws SettingsError if object couldn't be created + */ + private Object loadObject(String className, Class[] argsClass, + Object[] args) { + Object o = null; + Class objClass = getClass(className); + Constructor constructor; + + try { + if (argsClass != null) { // use a specific constructor + constructor = objClass.getConstructor((Class[])argsClass); + o = constructor.newInstance(args); + } + else { // call empty constructor + o = objClass.newInstance(); + } + } catch (SecurityException e) { + e.printStackTrace(); + throw new SettingsError("Fatal exception " + e, e); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + throw new SettingsError("Fatal exception " + e, e); + } catch (NoSuchMethodException e) { + throw new SettingsError("Class '" + className + + "' doesn't have a suitable constructor", e); + } catch (InstantiationException e) { + throw new SettingsError("Can't create an instance of '" + + className + "'", e); + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new SettingsError("Fatal exception " + e, e); + } catch (InvocationTargetException e) { + // this exception occurs if initialization of the object fails if (e.getCause() instanceof SettingsError) { throw (SettingsError)e.getCause(); } - else { - e.printStackTrace(); - throw new SimError("Couldn't create settings-accepting object"+ + else { + e.printStackTrace(); + throw new SimError("Couldn't create settings-accepting object"+ " for '" + className + "'\n" + "cause: " + e.getCause(), e); - } - } - - return o; - } - - /** - * Returns a Class object for the name of class of throws SettingsError - * if such class wasn't found. - * @param name Full name of the class (including package name) - * @return A Class object of that class - * @throws SettingsError if such class wasn't found or couldn't be loaded - */ - private Class getClass(String name) { - String className = name; - Class c; - - try { - c = Class.forName(className); - } catch (ClassNotFoundException e) { - throw new SettingsError("Couldn't find class '" + className + "'"+ - "\n" + e.getMessage(),e); - } - - return c; - } - - /** - * Fills a String formatted in a special way with values from Settings. - * String can contain (fully qualified) setting names surrounded by - * delimiters (see {@link #FILL_DELIMITER}). Values for those settings - * are retrieved and filled in the place of place holders. - * @param input The input string that may contain value requests - * @return A string filled with requested values (or the original string - * if no requests were found) - * @throws SettingsError if such settings were not found - */ - public String valueFillString(String input) { - if (!input.contains(FILL_DELIMITER)) { - return input; // nothing to fill - } - - Settings s = new Settings(); // don't use any namespace - String result = ""; - Scanner scan = new Scanner(input); - scan.useDelimiter(FILL_DELIMITER); - - if (input.startsWith(FILL_DELIMITER)) { - result += s.getSetting(scan.next()); - } - - while(scan.hasNext()) { - result += scan.next(); - if (!scan.hasNext()) { - break; - } - result += s.getSetting(scan.next()); - } - - return result; - } - - /** - * Returns a String representation of the stored settings - * @return a String representation of the stored settings - */ - public String toString() { - return props.toString(); - } - -} \ No newline at end of file + } + } + + return o; + } + + /** + * Returns a Class object for the name of class of throws SettingsError + * if such class wasn't found. + * @param name Full name of the class (including package name) + * @return A Class object of that class + * @throws SettingsError if such class wasn't found or couldn't be loaded + */ + private Class getClass(String name) { + String className = name; + Class c; + + try { + c = Class.forName(className); + } catch (ClassNotFoundException e) { + throw new SettingsError("Couldn't find class '" + className + "'"+ + "\n" + e.getMessage(),e); + } + + return c; + } + + /** + * Fills a String formatted in a special way with values from Settings. + * String can contain (fully qualified) setting names surrounded by + * delimiters (see {@link #FILL_DELIMITER}). Values for those settings + * are retrieved and filled in the place of place holders. + * @param input The input string that may contain value requests + * @return A string filled with requested values (or the original string + * if no requests were found) + * @throws SettingsError if such settings were not found + */ + public String valueFillString(String input) { + if (!input.contains(FILL_DELIMITER)) { + return input; // nothing to fill + } + + Settings s = new Settings(); // don't use any namespace + String result = ""; + Scanner scan = new Scanner(input); + scan.useDelimiter(FILL_DELIMITER); + + if (input.startsWith(FILL_DELIMITER)) { + result += s.getSetting(scan.next()); + } + + while(scan.hasNext()) { + result += scan.next(); + if (!scan.hasNext()) { + break; + } + result += s.getSetting(scan.next()); + } + + return result; + } + + /** + * Returns a String representation of the stored settings + * @return a String representation of the stored settings + */ + public String toString() { + return props.toString(); + } + +} diff --git a/core/SettingsError.java b/core/SettingsError.java index 5f4e42a18..e20085075 100644 --- a/core/SettingsError.java +++ b/core/SettingsError.java @@ -1,25 +1,25 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - -/** - * Settings related error - * - */ -public class SettingsError extends SimError { - - public SettingsError(String cause) { - super(cause); - } - - public SettingsError(String cause, Exception e) { - super(cause,e); - } - - public SettingsError(Exception e) { - super(e); - } - -} +package core; + +/** + * Settings related error + * + */ +public class SettingsError extends SimError { + + public SettingsError(String cause) { + super(cause); + } + + public SettingsError(String cause, Exception e) { + super(cause,e); + } + + public SettingsError(Exception e) { + super(e); + } + +} diff --git a/core/SimClock.java b/core/SimClock.java index d67c5fde2..788d7300d 100644 --- a/core/SimClock.java +++ b/core/SimClock.java @@ -1,50 +1,50 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package core; - -/** - * Wall clock for checking the simulation time. - */ -public class SimClock { - private static double clockTime = 0.0; + +/** + * Wall clock for checking the simulation time. + */ +public class SimClock { + private static double clockTime = 0.0; private static SimClock clock = null; - - private SimClock() {} - + + private SimClock() {} + static { - DTNSim.registerForReset(SimClock.class.getCanonicalName()); - reset(); - } - - /** - * Get the instance of the class that can also change the time. - * @return The instance of this clock - */ - public static SimClock getInstance() { - if (clock == null) { - clock = new SimClock(); - } - return clock; - } - - /** - * Returns the current time (seconds since start) - * @return Time as a double - */ - public static double getTime() { - return clockTime; - } - - /** - * Returns the current time rounded to the nearest integer - * @return Time as integer - */ - public static int getIntTime() { - return (int)Math.round(clockTime); - } - + DTNSim.registerForReset(SimClock.class.getCanonicalName()); + reset(); + } + + /** + * Get the instance of the class that can also change the time. + * @return The instance of this clock + */ + public static SimClock getInstance() { + if (clock == null) { + clock = new SimClock(); + } + return clock; + } + + /** + * Returns the current time (seconds since start) + * @return Time as a double + */ + public static double getTime() { + return clockTime; + } + + /** + * Returns the current time rounded to the nearest integer + * @return Time as integer + */ + public static int getIntTime() { + return (int)Math.round(clockTime); + } + /** * Returns a string presentation of the sim time shown with the given amount * of decimals @@ -54,35 +54,35 @@ public static int getIntTime() { public static String getFormattedTime(int decimals) { return String.format("%." + decimals + "f", clockTime); } - - /** - * Advances the time by n seconds - * @param time Nrof seconds to increase the time - */ - public void advance(double time) { - clockTime += time; - } - - /** - * Sets the time of the clock. - * @param time the time to set - */ - public void setTime(double time) { - clockTime = time; - } - - /** - * Returns the current simulation time in a string - * @return the current simulation time in a string - */ - public String toString() { - return "SimTime: " + clockTime; - } - - /** - * Resets the static fields of the class - */ - public static void reset() { - clockTime = 0; - } -} + + /** + * Advances the time by n seconds + * @param time Nrof seconds to increase the time + */ + public void advance(double time) { + clockTime += time; + } + + /** + * Sets the time of the clock. + * @param time the time to set + */ + public void setTime(double time) { + clockTime = time; + } + + /** + * Returns the current simulation time in a string + * @return the current simulation time in a string + */ + public String toString() { + return "SimTime: " + clockTime; + } + + /** + * Resets the static fields of the class + */ + public static void reset() { + clockTime = 0; + } +} diff --git a/core/SimError.java b/core/SimError.java index fdccc0500..9d60a127b 100644 --- a/core/SimError.java +++ b/core/SimError.java @@ -1,32 +1,32 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - -/** - * Error in the simulation - * - */ -public class SimError extends AssertionError { - private Exception e; - - public SimError(String cause) { - super(cause); - e = null; - } - - public SimError(String cause, Exception e) { - super(cause); - this.e = e; - } - - public SimError(Exception e) { - this(e.getMessage(),e); - } - - public Exception getException() { - return e; - } - -} +package core; + +/** + * Error in the simulation + * + */ +public class SimError extends AssertionError { + private Exception e; + + public SimError(String cause) { + super(cause); + e = null; + } + + public SimError(String cause, Exception e) { + super(cause); + this.e = e; + } + + public SimError(Exception e) { + this(e.getMessage(),e); + } + + public Exception getException() { + return e; + } + +} diff --git a/core/SimScenario.java b/core/SimScenario.java index b2fcf5767..8fc4a7038 100644 --- a/core/SimScenario.java +++ b/core/SimScenario.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2011 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - +package core; + import input.EventQueue; import input.EventQueueHandler; @@ -15,30 +15,30 @@ import movement.MovementModel; import movement.map.SimMap; import routing.MessageRouter; - -/** - * A simulation scenario used for getting and storing the settings of a - * simulation run. - */ + +/** + * A simulation scenario used for getting and storing the settings of a + * simulation run. + */ public class SimScenario implements Serializable { - - /** a way to get a hold of this... */ + + /** a way to get a hold of this... */ private static SimScenario myinstance=null; - - /** namespace of scenario settings ({@value})*/ - public static final String SCENARIO_NS = "Scenario"; - /** number of host groups -setting id ({@value})*/ - public static final String NROF_GROUPS_S = "nrofHostGroups"; + + /** namespace of scenario settings ({@value})*/ + public static final String SCENARIO_NS = "Scenario"; + /** number of host groups -setting id ({@value})*/ + public static final String NROF_GROUPS_S = "nrofHostGroups"; /** number of interface types -setting id ({@value})*/ public static final String NROF_INTTYPES_S = "nrofInterfaceTypes"; - /** scenario name -setting id ({@value})*/ - public static final String NAME_S = "name"; - /** end time -setting id ({@value})*/ - public static final String END_TIME_S = "endTime"; - /** update interval -setting id ({@value})*/ - public static final String UP_INT_S = "updateInterval"; - /** simulate connections -setting id ({@value})*/ - public static final String SIM_CON_S = "simulateConnections"; + /** scenario name -setting id ({@value})*/ + public static final String NAME_S = "name"; + /** end time -setting id ({@value})*/ + public static final String END_TIME_S = "endTime"; + /** update interval -setting id ({@value})*/ + public static final String UP_INT_S = "updateInterval"; + /** simulate connections -setting id ({@value})*/ + public static final String SIM_CON_S = "simulateConnections"; /** namespace for interface type settings ({@value}) */ public static final String INTTYPE_NS = "Interface"; @@ -53,119 +53,119 @@ public class SimScenario implements Serializable { public static final String APPTYPE_S = "type"; /** setting name for the number of applications */ public static final String APPCOUNT_S = "nrofApplications"; - - /** namespace for host group settings ({@value})*/ - public static final String GROUP_NS = "Group"; - /** group id -setting id ({@value})*/ - public static final String GROUP_ID_S = "groupID"; - /** number of hosts in the group -setting id ({@value})*/ - public static final String NROF_HOSTS_S = "nrofHosts"; - /** movement model class -setting id ({@value})*/ - public static final String MOVEMENT_MODEL_S = "movementModel"; - /** router class -setting id ({@value})*/ - public static final String ROUTER_S = "router"; + + /** namespace for host group settings ({@value})*/ + public static final String GROUP_NS = "Group"; + /** group id -setting id ({@value})*/ + public static final String GROUP_ID_S = "groupID"; + /** number of hosts in the group -setting id ({@value})*/ + public static final String NROF_HOSTS_S = "nrofHosts"; + /** movement model class -setting id ({@value})*/ + public static final String MOVEMENT_MODEL_S = "movementModel"; + /** router class -setting id ({@value})*/ + public static final String ROUTER_S = "router"; /** number of interfaces in the group -setting id ({@value})*/ public static final String NROF_INTERF_S = "nrofInterfaces"; /** interface name in the group -setting id ({@value})*/ public static final String INTERFACENAME_S = "interface"; /** application name in the group -setting id ({@value})*/ public static final String GAPPNAME_S = "application"; - - /** package where to look for movement models */ - private static final String MM_PACKAGE = "movement."; - /** package where to look for router classes */ - private static final String ROUTING_PACKAGE = "routing."; + + /** package where to look for movement models */ + private static final String MM_PACKAGE = "movement."; + /** package where to look for router classes */ + private static final String ROUTING_PACKAGE = "routing."; /** package where to look for interface classes */ private static final String INTTYPE_PACKAGE = "interfaces."; - + /** package where to look for application classes */ private static final String APP_PACKAGE = "applications."; - + /** The world instance */ - private World world; - /** List of hosts in this simulation */ - protected List hosts; - /** Name of the simulation */ - private String name; - /** number of host groups */ - int nrofGroups; - /** Width of the world */ - private int worldSizeX; - /** Height of the world */ - private int worldSizeY; - /** Largest host's radio range */ - private double maxHostRange; - /** Simulation end time */ - private double endTime; - /** Update interval of sim time */ - private double updateInterval; - /** External events queue */ - private EventQueueHandler eqHandler; - /** Should connections between hosts be simulated */ - private boolean simulateConnections; - /** Map used for host movement (if any) */ - private SimMap simMap; - - /** Global connection event listeners */ - private List connectionListeners; - /** Global message event listeners */ - private List messageListeners; - /** Global movement event listeners */ - private List movementListeners; - /** Global update event listeners */ + private World world; + /** List of hosts in this simulation */ + protected List hosts; + /** Name of the simulation */ + private String name; + /** number of host groups */ + int nrofGroups; + /** Width of the world */ + private int worldSizeX; + /** Height of the world */ + private int worldSizeY; + /** Largest host's radio range */ + private double maxHostRange; + /** Simulation end time */ + private double endTime; + /** Update interval of sim time */ + private double updateInterval; + /** External events queue */ + private EventQueueHandler eqHandler; + /** Should connections between hosts be simulated */ + private boolean simulateConnections; + /** Map used for host movement (if any) */ + private SimMap simMap; + + /** Global connection event listeners */ + private List connectionListeners; + /** Global message event listeners */ + private List messageListeners; + /** Global movement event listeners */ + private List movementListeners; + /** Global update event listeners */ private List updateListeners; /** Global application event listeners */ - private List appListeners; + private List appListeners; static { DTNSim.registerForReset(SimScenario.class.getCanonicalName()); reset(); } - + public static void reset() { myinstance = null; - } - - /** - * Creates a scenario based on Settings object. - */ - protected SimScenario() { - Settings s = new Settings(SCENARIO_NS); - nrofGroups = s.getInt(NROF_GROUPS_S); - - this.name = s.valueFillString(s.getSetting(NAME_S)); - this.endTime = s.getDouble(END_TIME_S); - this.updateInterval = s.getDouble(UP_INT_S); - this.simulateConnections = s.getBoolean(SIM_CON_S); - - s.ensurePositiveValue(nrofGroups, NROF_GROUPS_S); - s.ensurePositiveValue(endTime, END_TIME_S); - s.ensurePositiveValue(updateInterval, UP_INT_S); - - this.simMap = null; - this.maxHostRange = 1; - - this.connectionListeners = new ArrayList(); - this.messageListeners = new ArrayList(); - this.movementListeners = new ArrayList(); + } + + /** + * Creates a scenario based on Settings object. + */ + protected SimScenario() { + Settings s = new Settings(SCENARIO_NS); + nrofGroups = s.getInt(NROF_GROUPS_S); + + this.name = s.valueFillString(s.getSetting(NAME_S)); + this.endTime = s.getDouble(END_TIME_S); + this.updateInterval = s.getDouble(UP_INT_S); + this.simulateConnections = s.getBoolean(SIM_CON_S); + + s.ensurePositiveValue(nrofGroups, NROF_GROUPS_S); + s.ensurePositiveValue(endTime, END_TIME_S); + s.ensurePositiveValue(updateInterval, UP_INT_S); + + this.simMap = null; + this.maxHostRange = 1; + + this.connectionListeners = new ArrayList(); + this.messageListeners = new ArrayList(); + this.movementListeners = new ArrayList(); this.updateListeners = new ArrayList(); - this.appListeners = new ArrayList(); - this.eqHandler = new EventQueueHandler(); + this.appListeners = new ArrayList(); + this.eqHandler = new EventQueueHandler(); /* TODO: check size from movement models */ s.setNameSpace(MovementModel.MOVEMENT_MODEL_NS); int [] worldSize = s.getCsvInts(MovementModel.WORLD_SIZE, 2); this.worldSizeX = worldSize[0]; this.worldSizeY = worldSize[1]; - + createHosts(); - - this.world = new World(hosts, worldSizeX, worldSizeY, updateInterval, - updateListeners, simulateConnections, + + this.world = new World(hosts, worldSizeX, worldSizeY, updateInterval, + updateListeners, simulateConnections, eqHandler.getEventQueues()); } - + /** * Returns the SimScenario instance and creates one if it doesn't exist yet */ @@ -174,132 +174,132 @@ public static SimScenario getInstance() { myinstance = new SimScenario(); } return myinstance; - } - - - - /** - * Returns the name of the simulation run - * @return the name of the simulation run - */ - public String getName() { - return this.name; - } - - /** - * Returns true if connections should be simulated - * @return true if connections should be simulated (false if not) - */ - public boolean simulateConnections() { - return this.simulateConnections; - } - - /** - * Returns the width of the world - * @return the width of the world - */ - public int getWorldSizeX() { - return this.worldSizeX; - } - - /** - * Returns the height of the world - * @return the height of the world - */ - public int getWorldSizeY() { - return worldSizeY; - } - - /** - * Returns simulation's end time - * @return simulation's end time - */ - public double getEndTime() { - return endTime; - } - - /** - * Returns update interval (simulated seconds) of the simulation - * @return update interval (simulated seconds) of the simulation - */ - public double getUpdateInterval() { - return updateInterval; - } - - /** - * Returns how long range the hosts' radios have - * @return Range in meters - */ - public double getMaxHostRange() { - return maxHostRange; - } - - /** - * Returns the (external) event queue(s) of this scenario or null if there - * aren't any - * @return External event queues in a list or null - */ - public List getExternalEvents() { - return this.eqHandler.getEventQueues(); - } - - /** - * Returns the SimMap this scenario uses, or null if scenario doesn't - * use any map - * @return SimMap or null if no map is used - */ - public SimMap getMap() { - return this.simMap; - } - - /** - * Adds a new connection listener for all nodes - * @param cl The listener - */ - public void addConnectionListener(ConnectionListener cl){ - this.connectionListeners.add(cl); - } - - /** - * Adds a new message listener for all nodes - * @param ml The listener - */ - public void addMessageListener(MessageListener ml){ - this.messageListeners.add(ml); - } - - /** - * Adds a new movement listener for all nodes - * @param ml The listener - */ - public void addMovementListener(MovementListener ml){ - this.movementListeners.add(ml); - } - - /** - * Adds a new update listener for the world - * @param ul The listener - */ - public void addUpdateListener(UpdateListener ul) { - this.updateListeners.add(ul); - } - - /** - * Returns the list of registered update listeners - * @return the list of registered update listeners - */ - public List getUpdateListeners() { - return this.updateListeners; - } - - /** + } + + + + /** + * Returns the name of the simulation run + * @return the name of the simulation run + */ + public String getName() { + return this.name; + } + + /** + * Returns true if connections should be simulated + * @return true if connections should be simulated (false if not) + */ + public boolean simulateConnections() { + return this.simulateConnections; + } + + /** + * Returns the width of the world + * @return the width of the world + */ + public int getWorldSizeX() { + return this.worldSizeX; + } + + /** + * Returns the height of the world + * @return the height of the world + */ + public int getWorldSizeY() { + return worldSizeY; + } + + /** + * Returns simulation's end time + * @return simulation's end time + */ + public double getEndTime() { + return endTime; + } + + /** + * Returns update interval (simulated seconds) of the simulation + * @return update interval (simulated seconds) of the simulation + */ + public double getUpdateInterval() { + return updateInterval; + } + + /** + * Returns how long range the hosts' radios have + * @return Range in meters + */ + public double getMaxHostRange() { + return maxHostRange; + } + + /** + * Returns the (external) event queue(s) of this scenario or null if there + * aren't any + * @return External event queues in a list or null + */ + public List getExternalEvents() { + return this.eqHandler.getEventQueues(); + } + + /** + * Returns the SimMap this scenario uses, or null if scenario doesn't + * use any map + * @return SimMap or null if no map is used + */ + public SimMap getMap() { + return this.simMap; + } + + /** + * Adds a new connection listener for all nodes + * @param cl The listener + */ + public void addConnectionListener(ConnectionListener cl){ + this.connectionListeners.add(cl); + } + + /** + * Adds a new message listener for all nodes + * @param ml The listener + */ + public void addMessageListener(MessageListener ml){ + this.messageListeners.add(ml); + } + + /** + * Adds a new movement listener for all nodes + * @param ml The listener + */ + public void addMovementListener(MovementListener ml){ + this.movementListeners.add(ml); + } + + /** + * Adds a new update listener for the world + * @param ul The listener + */ + public void addUpdateListener(UpdateListener ul) { + this.updateListeners.add(ul); + } + + /** + * Returns the list of registered update listeners + * @return the list of registered update listeners + */ + public List getUpdateListeners() { + return this.updateListeners; + } + + /** * Adds a new application event listener for all nodes. * @param al The listener */ public void addApplicationListener(ApplicationListener al) { this.appListeners.add(al); } - + /** * Returns the list of registered application event listeners * @return the list of registered application event listeners @@ -307,46 +307,46 @@ public void addApplicationListener(ApplicationListener al) { public List getApplicationListeners() { return this.appListeners; } - - /** - * Creates hosts for the scenario - */ - protected void createHosts() { - this.hosts = new ArrayList(); - + + /** + * Creates hosts for the scenario + */ + protected void createHosts() { + this.hosts = new ArrayList(); + for (int i=1; i<=nrofGroups; i++) { - List interfaces = - new ArrayList(); - Settings s = new Settings(GROUP_NS+i); - s.setSecondaryNamespace(GROUP_NS); - String gid = s.getSetting(GROUP_ID_S); + List interfaces = + new ArrayList(); + Settings s = new Settings(GROUP_NS+i); + s.setSecondaryNamespace(GROUP_NS); + String gid = s.getSetting(GROUP_ID_S); int nrofHosts = s.getInt(NROF_HOSTS_S); - int nrofInterfaces = s.getInt(NROF_INTERF_S); - int appCount; - - // creates prototypes of MessageRouter and MovementModel - MovementModel mmProto = - (MovementModel)s.createIntializedObject(MM_PACKAGE + - s.getSetting(MOVEMENT_MODEL_S)); - MessageRouter mRouterProto = - (MessageRouter)s.createIntializedObject(ROUTING_PACKAGE + + int nrofInterfaces = s.getInt(NROF_INTERF_S); + int appCount; + + // creates prototypes of MessageRouter and MovementModel + MovementModel mmProto = + (MovementModel)s.createIntializedObject(MM_PACKAGE + + s.getSetting(MOVEMENT_MODEL_S)); + MessageRouter mRouterProto = + (MessageRouter)s.createIntializedObject(ROUTING_PACKAGE + s.getSetting(ROUTER_S)); - - /* checks that these values are positive (throws Error if not) */ - s.ensurePositiveValue(nrofHosts, NROF_HOSTS_S); + + /* checks that these values are positive (throws Error if not) */ + s.ensurePositiveValue(nrofHosts, NROF_HOSTS_S); s.ensurePositiveValue(nrofInterfaces, NROF_INTERF_S); // setup interfaces for (int j=1;j<=nrofInterfaces;j++) { String intName = s.getSetting(INTERFACENAME_S + j); - Settings intSettings = new Settings(intName); - NetworkInterface iface = + Settings intSettings = new Settings(intName); + NetworkInterface iface = (NetworkInterface)intSettings.createIntializedObject( INTTYPE_PACKAGE +intSettings.getSetting(INTTYPE_S)); iface.setClisteners(connectionListeners); iface.setGroupSettings(s); interfaces.add(iface); - } + } // setup applications if (s.contains(APPCOUNT_S)) { @@ -376,40 +376,40 @@ protected void createHosts() { System.err.println("Caught at " + se.getStackTrace()[0]); System.exit(-1); } - } - - if (mmProto instanceof MapBasedMovement) { - this.simMap = ((MapBasedMovement)mmProto).getMap(); - } - - // creates hosts of ith group - for (int j=0; j getHosts() { - return this.hosts; + + // prototypes are given to new DTNHost which replicates + // new instances of movement model and message router + DTNHost host = new DTNHost(this.messageListeners, + this.movementListeners, gid, interfaces, comBus, + mmProto, mRouterProto); + hosts.add(host); + } + } } - + + /** + * Returns the list of nodes for this scenario. + * @return the list of nodes for this scenario. + */ + public List getHosts() { + return this.hosts; + } + /** * Returns the World object of this scenario * @return the World object */ public World getWorld() { return this.world; - } - -} \ No newline at end of file + } + +} diff --git a/core/UpdateListener.java b/core/UpdateListener.java index 276d7cae6..83b52a50f 100644 --- a/core/UpdateListener.java +++ b/core/UpdateListener.java @@ -1,24 +1,24 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - +package core; + import java.util.List; - -/** - * Interface for classes that want to be informed about every single update + +/** + * Interface for classes that want to be informed about every single update * call to the World object.
- * NOTE: if update interval is large (if, e.g., no movement or + * NOTE: if update interval is large (if, e.g., no movement or * connection simulation is needed), update listeners may not get called at all - * during the simulation. - */ -public interface UpdateListener { - - /** - * Method is called on every update cycle. - * @param hosts A list of all hosts in the world - */ - public void updated(List hosts); - -} + * during the simulation. + */ +public interface UpdateListener { + + /** + * Method is called on every update cycle. + * @param hosts A list of all hosts in the world + */ + public void updated(List hosts); + +} diff --git a/core/VBRConnection.java b/core/VBRConnection.java index 6750e2130..c2ad1603a 100644 --- a/core/VBRConnection.java +++ b/core/VBRConnection.java @@ -1,113 +1,113 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package core; - -import routing.MessageRouter; - -/** - * A connection between two DTN nodes. The transmission speed - * is updated every round from the end point transmission speeds - */ -public class VBRConnection extends Connection { - private int msgsize; - private int msgsent; - private int currentspeed = 0; - private double lastUpdate = 0; - - - /** - * Creates a new connection between nodes and sets the connection - * state to "up". - * @param fromNode The node that initiated the connection - * @param fromInterface The interface that initiated the connection - * @param toNode The node in the other side of the connection - * @param toInterface The interface in the other side of the connection - */ - public VBRConnection(DTNHost fromNode, NetworkInterface fromInterface, - DTNHost toNode, NetworkInterface toInterface) { - super(fromNode, fromInterface, toNode, toInterface); - this.msgsent = 0; - } - - /** - * Sets a message that this connection is currently transferring. If message - * passing is controlled by external events, this method is not needed - * (but then e.g. {@link #finalizeTransfer()} and - * {@link #isMessageTransferred()} will not work either). Only a one message - * at a time can be transferred using one connection. - * @param from The host sending the message - * @param m The message - * @return The value returned by - * {@link MessageRouter#receiveMessage(Message, DTNHost)} - */ - public int startTransfer(DTNHost from, Message m) { - assert this.msgOnFly == null : "Already transferring " + - this.msgOnFly + " from " + this.msgFromNode + " to " + - this.getOtherNode(this.msgFromNode) + ". Can't "+ - "start transfer of " + m + " from " + from; - - this.msgFromNode = from; - Message newMessage = m.replicate(); - int retVal = getOtherNode(from).receiveMessage(newMessage, from); - - if (retVal == MessageRouter.RCV_OK) { - this.msgOnFly = newMessage; - this.msgsize = m.getSize(); - this.msgsent = 0; - } - - return retVal; - } - - /** - * Calculate the current transmission speed from the information - * given by the interfaces, and calculate the missing data amount. - * - */ - public void update() { - currentspeed = this.fromInterface.getTransmitSpeed(toInterface); - int othspeed = this.toInterface.getTransmitSpeed(fromInterface); - double now = core.SimClock.getTime(); - - if (othspeed < currentspeed) { - currentspeed = othspeed; - } - - - msgsent += currentspeed * (now - this.lastUpdate); - this.lastUpdate = now; - } - - /** - * returns the current speed of the connection - */ - public double getSpeed() { - return this.currentspeed; - } - - /** - * Returns the amount of bytes to be transferred before ongoing transfer - * is ready or 0 if there's no ongoing transfer or it has finished - * already - * @return the amount of bytes to be transferred - */ - public int getRemainingByteCount() { - int bytesLeft = msgsize - msgsent; - return (bytesLeft > 0 ? bytesLeft : 0); - } - - /** - * Returns true if the current message transfer is done. - * @return True if the transfer is done, false if not - */ - public boolean isMessageTransferred() { - if (msgsent >= msgsize) { - return true; - } else { - return false; - } - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import routing.MessageRouter; + +/** + * A connection between two DTN nodes. The transmission speed + * is updated every round from the end point transmission speeds + */ +public class VBRConnection extends Connection { + private int msgsize; + private int msgsent; + private int currentspeed = 0; + private double lastUpdate = 0; + + + /** + * Creates a new connection between nodes and sets the connection + * state to "up". + * @param fromNode The node that initiated the connection + * @param fromInterface The interface that initiated the connection + * @param toNode The node in the other side of the connection + * @param toInterface The interface in the other side of the connection + */ + public VBRConnection(DTNHost fromNode, NetworkInterface fromInterface, + DTNHost toNode, NetworkInterface toInterface) { + super(fromNode, fromInterface, toNode, toInterface); + this.msgsent = 0; + } + + /** + * Sets a message that this connection is currently transferring. If message + * passing is controlled by external events, this method is not needed + * (but then e.g. {@link #finalizeTransfer()} and + * {@link #isMessageTransferred()} will not work either). Only a one message + * at a time can be transferred using one connection. + * @param from The host sending the message + * @param m The message + * @return The value returned by + * {@link MessageRouter#receiveMessage(Message, DTNHost)} + */ + public int startTransfer(DTNHost from, Message m) { + assert this.msgOnFly == null : "Already transferring " + + this.msgOnFly + " from " + this.msgFromNode + " to " + + this.getOtherNode(this.msgFromNode) + ". Can't "+ + "start transfer of " + m + " from " + from; + + this.msgFromNode = from; + Message newMessage = m.replicate(); + int retVal = getOtherNode(from).receiveMessage(newMessage, from); + + if (retVal == MessageRouter.RCV_OK) { + this.msgOnFly = newMessage; + this.msgsize = m.getSize(); + this.msgsent = 0; + } + + return retVal; + } + + /** + * Calculate the current transmission speed from the information + * given by the interfaces, and calculate the missing data amount. + * + */ + public void update() { + currentspeed = this.fromInterface.getTransmitSpeed(toInterface); + int othspeed = this.toInterface.getTransmitSpeed(fromInterface); + double now = core.SimClock.getTime(); + + if (othspeed < currentspeed) { + currentspeed = othspeed; + } + + + msgsent += currentspeed * (now - this.lastUpdate); + this.lastUpdate = now; + } + + /** + * returns the current speed of the connection + */ + public double getSpeed() { + return this.currentspeed; + } + + /** + * Returns the amount of bytes to be transferred before ongoing transfer + * is ready or 0 if there's no ongoing transfer or it has finished + * already + * @return the amount of bytes to be transferred + */ + public int getRemainingByteCount() { + int bytesLeft = msgsize - msgsent; + return (bytesLeft > 0 ? bytesLeft : 0); + } + + /** + * Returns true if the current message transfer is done. + * @return True if the transfer is done, false if not + */ + public boolean isMessageTransferred() { + if (msgsent >= msgsize) { + return true; + } else { + return false; + } + } + +} diff --git a/core/World.java b/core/World.java index ebdcdc381..c3c4dbcc4 100644 --- a/core/World.java +++ b/core/World.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package core; - +package core; + import input.EventQueue; import input.ExternalEvent; import input.ScheduledUpdatesQueue; @@ -12,77 +12,77 @@ import java.util.Collections; import java.util.List; import java.util.Random; - -/** - * World contains all the nodes and is responsible for updating their - * location and connections. - */ + +/** + * World contains all the nodes and is responsible for updating their + * location and connections. + */ public class World { /** name space of optimization settings ({@value})*/ public static final String OPTIMIZATION_SETTINGS_NS = "Optimization"; /** - * Should the order of node updates be different (random) within every - * update step -setting id ({@value}). Boolean (true/false) variable. + * Should the order of node updates be different (random) within every + * update step -setting id ({@value}). Boolean (true/false) variable. * Default is @link {@link #DEF_RANDOMIZE_UPDATES}. */ public static final String RANDOMIZE_UPDATES_S = "randomizeUpdateOrder"; /** should the update order of nodes be randomized -setting's default value * ({@value}) */ public static final boolean DEF_RANDOMIZE_UPDATES = true; - + /** - * Should the connectivity simulation be stopped after one round - * -setting id ({@value}). Boolean (true/false) variable. + * Should the connectivity simulation be stopped after one round + * -setting id ({@value}). Boolean (true/false) variable. */ public static final String SIMULATE_CON_ONCE_S = "simulateConnectionsOnce"; - private int sizeX; - private int sizeY; - private List eventQueues; - private double updateInterval; - private SimClock simClock; + private int sizeX; + private int sizeY; + private List eventQueues; + private double updateInterval; + private SimClock simClock; private double nextQueueEventTime; private EventQueue nextEventQueue; - /** list of nodes; nodes are indexed by their network address */ - private List hosts; + /** list of nodes; nodes are indexed by their network address */ + private List hosts; private boolean simulateConnections; - /** nodes in the order they should be updated (if the order should be + /** nodes in the order they should be updated (if the order should be * randomized; null value means that the order should not be randomized) */ - private ArrayList updateOrder; + private ArrayList updateOrder; /** is cancellation of simulation requested from UI */ - private boolean isCancelled; + private boolean isCancelled; private List updateListeners; /** Queue of scheduled update requests */ private ScheduledUpdatesQueue scheduledUpdates; private boolean simulateConOnce; - - /** - * Constructor. - */ - public World(List hosts, int sizeX, int sizeY, + + /** + * Constructor. + */ + public World(List hosts, int sizeX, int sizeY, double updateInterval, List updateListeners, boolean simulateConnections, List eventQueues) { this.hosts = hosts; this.sizeX = sizeX; - this.sizeY = sizeY; - this.updateInterval = updateInterval; - this.updateListeners = updateListeners; - this.simulateConnections = simulateConnections; - this.eventQueues = eventQueues; - + this.sizeY = sizeY; + this.updateInterval = updateInterval; + this.updateListeners = updateListeners; + this.simulateConnections = simulateConnections; + this.eventQueues = eventQueues; + this.simClock = SimClock.getInstance(); this.scheduledUpdates = new ScheduledUpdatesQueue(); this.isCancelled = false; - + setNextEventQueue(); initSettings(); - } + } - /** - * Initializes settings fields that can be configured using Settings class - */ - private void initSettings() { + /** + * Initializes settings fields that can be configured using Settings class + */ + private void initSettings() { Settings s = new Settings(OPTIMIZATION_SETTINGS_NS); boolean randomizeUpdates = DEF_RANDOMIZE_UPDATES; @@ -90,40 +90,40 @@ private void initSettings() { randomizeUpdates = s.getBoolean(RANDOMIZE_UPDATES_S); } simulateConOnce = s.getBoolean(SIMULATE_CON_ONCE_S, false); - + if(randomizeUpdates) { // creates the update order array that can be shuffled this.updateOrder = new ArrayList(this.hosts); } else { // null pointer means "don't randomize" this.updateOrder = null; - } - } - - /** - * Moves hosts in the world for the time given time initialize host - * positions properly. SimClock must be set to -time before - * calling this method. - * @param time The total time (seconds) to move - */ - public void warmupMovementModel(double time) { - if (time <= 0) { - return; - } - - while(SimClock.getTime() < -updateInterval) { - moveHosts(updateInterval); - simClock.advance(updateInterval); - } - - double finalStep = -SimClock.getTime(); - - moveHosts(finalStep); - simClock.setTime(0); - } + } + } + + /** + * Moves hosts in the world for the time given time initialize host + * positions properly. SimClock must be set to -time before + * calling this method. + * @param time The total time (seconds) to move + */ + public void warmupMovementModel(double time) { + if (time <= 0) { + return; + } + + while(SimClock.getTime() < -updateInterval) { + moveHosts(updateInterval); + simClock.advance(updateInterval); + } + + double finalStep = -SimClock.getTime(); + + moveHosts(finalStep); + simClock.setTime(0); + } /** - * Goes through all event Queues and sets the + * Goes through all event Queues and sets the * event queue that has the next event. */ public void setNextEventQueue() { @@ -133,7 +133,7 @@ public void setNextEventQueue() { /* find the queue that has the next event */ for (EventQueue eq : eventQueues) { if (eq.nextEventsTime() < earliest){ - nextQueue = eq; + nextQueue = eq; earliest = eq.nextEventsTime(); } } @@ -141,36 +141,36 @@ public void setNextEventQueue() { this.nextEventQueue = nextQueue; this.nextQueueEventTime = earliest; } - - /** - * Update (move, connect, disconnect etc.) all hosts in the world. + + /** + * Update (move, connect, disconnect etc.) all hosts in the world. * Runs all external events that are due between the time when - * this method is called and after one update interval. - */ - public void update () { - double runUntil = SimClock.getTime() + this.updateInterval; + * this method is called and after one update interval. + */ + public void update () { + double runUntil = SimClock.getTime() + this.updateInterval; setNextEventQueue(); - + /* process all events that are due until next interval update */ while (this.nextQueueEventTime <= runUntil) { simClock.setTime(this.nextQueueEventTime); - ExternalEvent ee = this.nextEventQueue.nextEvent(); + ExternalEvent ee = this.nextEventQueue.nextEvent(); ee.processEvent(this); updateHosts(); // update all hosts after every event - setNextEventQueue(); - } + setNextEventQueue(); + } - moveHosts(this.updateInterval); + moveHosts(this.updateInterval); simClock.setTime(runUntil); updateHosts(); - - /* inform all update listeners */ - for (UpdateListener ul : this.updateListeners) { - ul.updated(this.hosts); - } - } + + /* inform all update listeners */ + for (UpdateListener ul : this.updateListeners) { + ul.updated(this.hosts); + } + } /** * Updates all hosts (calls update for every one of them). If update @@ -187,89 +187,89 @@ private void updateHosts() { } } else { // update order randomizing is on - assert this.updateOrder.size() == this.hosts.size() : + assert this.updateOrder.size() == this.hosts.size() : "Nrof hosts has changed unexpectedly"; Random rng = new Random(SimClock.getIntTime()); - Collections.shuffle(this.updateOrder, rng); + Collections.shuffle(this.updateOrder, rng); for (int i=0, n = hosts.size();i < n; i++) { if (this.isCancelled) { break; } this.updateOrder.get(i).update(simulateConnections); - } + } } - + if (simulateConOnce && simulateConnections) { simulateConnections = false; } } - - /** - * Moves all hosts in the world for a given amount of time - * @param timeIncrement The time how long all nodes should move - */ - private void moveHosts(double timeIncrement) { - for (int i=0,n = hosts.size(); i getHosts() { - return this.hosts; - } - - /** - * Returns the x-size (width) of the world - * @return the x-size (width) of the world - */ - public int getSizeX() { - return this.sizeX; - } - - /** - * Returns the y-size (height) of the world - * @return the y-size (height) of the world - */ - public int getSizeY() { - return this.sizeY; - } - - /** - * Returns a node from the world by its address - * @param address The address of the node - * @return The requested node or null if it wasn't found - */ - public DTNHost getNodeByAddress(int address) { - if (address < 0 || address >= hosts.size()) { - throw new SimError("No host for address " + address + ". Address " + - "range of 0-" + (hosts.size()-1) + " is valid"); - } - - DTNHost node = this.hosts.get(address); - assert node.getAddress() == address : "Node indexing failed. " + - "Node " + node + " in index " + address; - - return node; - } /** - * Schedules an update request to all nodes to happen at the specified + * Moves all hosts in the world for a given amount of time + * @param timeIncrement The time how long all nodes should move + */ + private void moveHosts(double timeIncrement) { + for (int i=0,n = hosts.size(); i getHosts() { + return this.hosts; + } + + /** + * Returns the x-size (width) of the world + * @return the x-size (width) of the world + */ + public int getSizeX() { + return this.sizeX; + } + + /** + * Returns the y-size (height) of the world + * @return the y-size (height) of the world + */ + public int getSizeY() { + return this.sizeY; + } + + /** + * Returns a node from the world by its address + * @param address The address of the node + * @return The requested node or null if it wasn't found + */ + public DTNHost getNodeByAddress(int address) { + if (address < 0 || address >= hosts.size()) { + throw new SimError("No host for address " + address + ". Address " + + "range of 0-" + (hosts.size()-1) + " is valid"); + } + + DTNHost node = this.hosts.get(address); + assert node.getAddress() == address : "Node indexing failed. " + + "Node " + node + " in index " + address; + + return node; + } + + /** + * Schedules an update request to all nodes to happen at the specified * simulation time. * @param simTime The time of the update */ public void scheduleUpdate(double simTime) { scheduledUpdates.addUpdate(simTime); - } -} + } +} diff --git a/core/package.html b/core/package.html index 81ea38f32..56ab9f991 100644 --- a/core/package.html +++ b/core/package.html @@ -1,14 +1,14 @@ - - - - -Contains core classes and interfaces of the simulator. - -Almost all of these classes are needed for every run of the simulator. -DTNSim is the main class of the program. It starts up a proper user interface -which in turn starts the simulation. - -@see ui.DTNSimUI - - - \ No newline at end of file + + + + +Contains core classes and interfaces of the simulator. + +Almost all of these classes are needed for every run of the simulator. +DTNSim is the main class of the program. It starts up a proper user interface +which in turn starts the simulation. + +@see ui.DTNSimUI + + + diff --git a/data/CentralPOIs.wkt b/data/CentralPOIs.wkt index 5167d943e..2519079f4 100644 --- a/data/CentralPOIs.wkt +++ b/data/CentralPOIs.wkt @@ -4,4 +4,4 @@ POINT (2552275.9398973365 6673509.820852942) POINT (2552361.289603607 6673630.088457832) -POINT (2552782.3212060533 6673285.5993876355) \ No newline at end of file +POINT (2552782.3212060533 6673285.5993876355) diff --git a/data/HelsinkiMedium/A_bus.wkt b/data/HelsinkiMedium/A_bus.wkt index ff8a92e55..d7c4fed7d 100644 --- a/data/HelsinkiMedium/A_bus.wkt +++ b/data/HelsinkiMedium/A_bus.wkt @@ -1,2 +1,2 @@ -LINESTRING (2553558.1158829676 6674022.108437747, 2553256.4880741183 6674002.824011413, 2552932.8422519267 6673978.828503751, 2552757.3251099777 6673680.650063182, 2552363.5334775783 6673567.544102095, 2552275.651163554 6673509.600802434, 2551892.3364427104 6673318.977048773, 2552122.746001586 6673002.154328803, 2552264.671030261 6672803.6187591525, 2552483.811722061 6672500.92928317, - 2552253.088680792 6672172.793966631) \ No newline at end of file +LINESTRING (2553558.1158829676 6674022.108437747, 2553256.4880741183 6674002.824011413, 2552932.8422519267 6673978.828503751, 2552757.3251099777 6673680.650063182, 2552363.5334775783 6673567.544102095, 2552275.651163554 6673509.600802434, 2551892.3364427104 6673318.977048773, 2552122.746001586 6673002.154328803, 2552264.671030261 6672803.6187591525, 2552483.811722061 6672500.92928317, + 2552253.088680792 6672172.793966631) diff --git a/data/HelsinkiMedium/A_homes.wkt b/data/HelsinkiMedium/A_homes.wkt index e1789ca07..76953a5ab 100644 --- a/data/HelsinkiMedium/A_homes.wkt +++ b/data/HelsinkiMedium/A_homes.wkt @@ -280,4 +280,4 @@ POINT (2552850.64386866 6672373.590055137) POINT (2552608.387975143 6671893.399837605) -POINT (2553619.970908834 6672194.188877382) \ No newline at end of file +POINT (2553619.970908834 6672194.188877382) diff --git a/data/HelsinkiMedium/A_meetingspots.wkt b/data/HelsinkiMedium/A_meetingspots.wkt index a49b45d41..69d776a95 100644 --- a/data/HelsinkiMedium/A_meetingspots.wkt +++ b/data/HelsinkiMedium/A_meetingspots.wkt @@ -4,4 +4,4 @@ POINT (2552398.0412894213 6673352.814815518) POINT (2552271.1386670014 6673506.220026447) -POINT (2552747.310172474 6672343.373119477) \ No newline at end of file +POINT (2552747.310172474 6672343.373119477) diff --git a/data/HelsinkiMedium/A_offices.wkt b/data/HelsinkiMedium/A_offices.wkt index 0a8d77521..b7c77db94 100644 --- a/data/HelsinkiMedium/A_offices.wkt +++ b/data/HelsinkiMedium/A_offices.wkt @@ -56,4 +56,4 @@ POINT (2552250.077599912 6673094.855606426) POINT (2552478.6805102592 6673256.062608091) -POINT (2552844.266976823 6672450.797776541) \ No newline at end of file +POINT (2552844.266976823 6672450.797776541) diff --git a/data/HelsinkiMedium/B_bus.wkt b/data/HelsinkiMedium/B_bus.wkt index d4b4091a4..2801c672b 100644 --- a/data/HelsinkiMedium/B_bus.wkt +++ b/data/HelsinkiMedium/B_bus.wkt @@ -1,2 +1,2 @@ -LINESTRING (2549711.7116691247 6672521.834081425, 2549326.1448247735 6672446.546800818, 2548919.9211406293 6672451.737992347, 2548857.076170364 6672141.0166728245, 2549038.92070693 6671689.052934085, 2549125.4665960157 6671310.466037451, 2548826.6848773137 6671777.543245168, 2548721.940510359 6672165.17221722, 2548776.5689421124 6672470.202230424, 2548598.576939166 6672504.560116551, - 2548409.3490672903 6672539.118048595, 2548204.9172993526 6672577.186786471, 2547920.50627351 6672635.070072358, 2547945.8323510517 6672417.580152135, 2548008.8175634407 6672181.105874455, 2547895.0977006014 6671978.22930842) \ No newline at end of file +LINESTRING (2549711.7116691247 6672521.834081425, 2549326.1448247735 6672446.546800818, 2548919.9211406293 6672451.737992347, 2548857.076170364 6672141.0166728245, 2549038.92070693 6671689.052934085, 2549125.4665960157 6671310.466037451, 2548826.6848773137 6671777.543245168, 2548721.940510359 6672165.17221722, 2548776.5689421124 6672470.202230424, 2548598.576939166 6672504.560116551, + 2548409.3490672903 6672539.118048595, 2548204.9172993526 6672577.186786471, 2547920.50627351 6672635.070072358, 2547945.8323510517 6672417.580152135, 2548008.8175634407 6672181.105874455, 2547895.0977006014 6671978.22930842) diff --git a/data/HelsinkiMedium/B_homes.wkt b/data/HelsinkiMedium/B_homes.wkt index 8ef6dc479..47d67c13d 100644 --- a/data/HelsinkiMedium/B_homes.wkt +++ b/data/HelsinkiMedium/B_homes.wkt @@ -238,4 +238,4 @@ POINT (2548841.591790056 6671231.327872955) POINT (2548324.791316539 6672456.579103522) -POINT (2548615.777223099 6672593.840609004) \ No newline at end of file +POINT (2548615.777223099 6672593.840609004) diff --git a/data/HelsinkiMedium/B_meetingspots.wkt b/data/HelsinkiMedium/B_meetingspots.wkt index c5fe0ca7b..9a7f978e7 100644 --- a/data/HelsinkiMedium/B_meetingspots.wkt +++ b/data/HelsinkiMedium/B_meetingspots.wkt @@ -1 +1 @@ -POINT (2548669.62194887 6672165.182219516) \ No newline at end of file +POINT (2548669.62194887 6672165.182219516) diff --git a/data/HelsinkiMedium/B_offices.wkt b/data/HelsinkiMedium/B_offices.wkt index 1c6e61331..43f15b1c5 100644 --- a/data/HelsinkiMedium/B_offices.wkt +++ b/data/HelsinkiMedium/B_offices.wkt @@ -16,4 +16,4 @@ POINT (2549125.4665960157 6671310.466037451) POINT (2548899.0168147366 6671469.6525753625) -POINT (2549038.92070693 6671689.052934085) \ No newline at end of file +POINT (2549038.92070693 6671689.052934085) diff --git a/data/HelsinkiMedium/C_bus.wkt b/data/HelsinkiMedium/C_bus.wkt index c6102e8c2..d8064d00b 100644 --- a/data/HelsinkiMedium/C_bus.wkt +++ b/data/HelsinkiMedium/C_bus.wkt @@ -1,2 +1,2 @@ -LINESTRING (2551844.6623703605 6674216.3330179015, 2551557.9002265697 6674544.118254086, 2551245.6800126503 6674810.619423806, 2551126.16072554 6675032.970459795, 2551042.675414555 6675236.6272049025, 2550817.5785572873 6675557.160776621, 2550277.86912047 6675871.0628262125, 2549830.537995156 6676063.476990825, 2549305.5374822007 6676406.915819961, 2548940.256248493 6676559.490840337, - 2548569.3983280044 6677113.988113486) \ No newline at end of file +LINESTRING (2551844.6623703605 6674216.3330179015, 2551557.9002265697 6674544.118254086, 2551245.6800126503 6674810.619423806, 2551126.16072554 6675032.970459795, 2551042.675414555 6675236.6272049025, 2550817.5785572873 6675557.160776621, 2550277.86912047 6675871.0628262125, 2549830.537995156 6676063.476990825, 2549305.5374822007 6676406.915819961, 2548940.256248493 6676559.490840337, + 2548569.3983280044 6677113.988113486) diff --git a/data/HelsinkiMedium/C_homes.wkt b/data/HelsinkiMedium/C_homes.wkt index 0ceca8213..6a3a60a8f 100644 --- a/data/HelsinkiMedium/C_homes.wkt +++ b/data/HelsinkiMedium/C_homes.wkt @@ -186,4 +186,4 @@ POINT (2551657.6371247726 6675606.672140909) POINT (2550018.5036879224 6675800.976739431) -POINT (2549939.365882756 6675948.670639449) \ No newline at end of file +POINT (2549939.365882756 6675948.670639449) diff --git a/data/HelsinkiMedium/C_meetingspots.wkt b/data/HelsinkiMedium/C_meetingspots.wkt index 3c3cec952..e902d6336 100644 --- a/data/HelsinkiMedium/C_meetingspots.wkt +++ b/data/HelsinkiMedium/C_meetingspots.wkt @@ -1,3 +1,3 @@ POINT (2551019.4859670075 6675223.744247892) -POINT (2551776.083972117 6676132.332795221) \ No newline at end of file +POINT (2551776.083972117 6676132.332795221) diff --git a/data/HelsinkiMedium/C_offices.wkt b/data/HelsinkiMedium/C_offices.wkt index 5c42fe405..9cbc004a4 100644 --- a/data/HelsinkiMedium/C_offices.wkt +++ b/data/HelsinkiMedium/C_offices.wkt @@ -36,4 +36,4 @@ POINT (2550826.0508314357 6675180.984433278) POINT (2550853.835270902 6674980.93851696) -POINT (2550585.040617954 6675171.722307353) \ No newline at end of file +POINT (2550585.040617954 6675171.722307353) diff --git a/data/HelsinkiMedium/D_bus.wkt b/data/HelsinkiMedium/D_bus.wkt index 91da8b1ae..cd4c3d475 100644 --- a/data/HelsinkiMedium/D_bus.wkt +++ b/data/HelsinkiMedium/D_bus.wkt @@ -1 +1 @@ -LINESTRING (2553320.273491563 6674457.528379207, 2553719.84804916 6675104.546888653, 2553670.9035481643 6675714.12680486, 2553683.145860566 6676146.346011659, 2553528.33505563 6676650.701775882, 2553727.5943640824 6677300.7809878485) \ No newline at end of file +LINESTRING (2553320.273491563 6674457.528379207, 2553719.84804916 6675104.546888653, 2553670.9035481643 6675714.12680486, 2553683.145860566 6676146.346011659, 2553528.33505563 6676650.701775882, 2553727.5943640824 6677300.7809878485) diff --git a/data/HelsinkiMedium/D_homes.wkt b/data/HelsinkiMedium/D_homes.wkt index 29285b3d7..5914b6df3 100644 --- a/data/HelsinkiMedium/D_homes.wkt +++ b/data/HelsinkiMedium/D_homes.wkt @@ -242,4 +242,4 @@ POINT (2552211.8574965727 6677157.938201302) POINT (2552070.9719095165 6676855.328743686) -POINT (2551526.3952460703 6675568.953483388) \ No newline at end of file +POINT (2551526.3952460703 6675568.953483388) diff --git a/data/HelsinkiMedium/D_meetingspots.wkt b/data/HelsinkiMedium/D_meetingspots.wkt index 8c2c40054..93721c1e9 100644 --- a/data/HelsinkiMedium/D_meetingspots.wkt +++ b/data/HelsinkiMedium/D_meetingspots.wkt @@ -1,3 +1,3 @@ POINT (2553423.037969719 6674726.15003564) -POINT (2551506.1838812567 6676962.873428298) \ No newline at end of file +POINT (2551506.1838812567 6676962.873428298) diff --git a/data/HelsinkiMedium/D_offices.wkt b/data/HelsinkiMedium/D_offices.wkt index 17e0dc2d1..a8c35ce9f 100644 --- a/data/HelsinkiMedium/D_offices.wkt +++ b/data/HelsinkiMedium/D_offices.wkt @@ -36,4 +36,4 @@ POINT (2553890.89394224 6675364.116467373) POINT (2554326.5684722555 6675869.682509391) -POINT (2553932.7438417096 6677359.32442526) \ No newline at end of file +POINT (2553932.7438417096 6677359.32442526) diff --git a/data/HelsinkiMedium/E_bus.wkt b/data/HelsinkiMedium/E_bus.wkt index fcc880ca1..027b5a658 100644 --- a/data/HelsinkiMedium/E_bus.wkt +++ b/data/HelsinkiMedium/E_bus.wkt @@ -1,2 +1,2 @@ -LINESTRING (2548008.8175634407 6672181.105874455, 2547920.7125119264 6672681.830805297, 2548383.8002522583 6672630.819096636, 2549125.219109916 6672924.776568371, 2550869.4433942605 6673004.914962448, 2551317.2612422374 6672889.818544494, 2551612.3884162 6672988.061093998, 2551699.751009415 6673299.7926453985, 2551893.5491245994 6673447.066448992, 2552153.657015446 6673654.484057328, - 2552256.454491749 6673534.296470803, 2552719.2287496882 6673650.273090789, 2553233.3316247175 6673542.7184038805) \ No newline at end of file +LINESTRING (2548008.8175634407 6672181.105874455, 2547920.7125119264 6672681.830805297, 2548383.8002522583 6672630.819096636, 2549125.219109916 6672924.776568371, 2550869.4433942605 6673004.914962448, 2551317.2612422374 6672889.818544494, 2551612.3884162 6672988.061093998, 2551699.751009415 6673299.7926453985, 2551893.5491245994 6673447.066448992, 2552153.657015446 6673654.484057328, + 2552256.454491749 6673534.296470803, 2552719.2287496882 6673650.273090789, 2553233.3316247175 6673542.7184038805) diff --git a/data/HelsinkiMedium/E_homes.wkt b/data/HelsinkiMedium/E_homes.wkt index e9c327f85..ad0dd108c 100644 --- a/data/HelsinkiMedium/E_homes.wkt +++ b/data/HelsinkiMedium/E_homes.wkt @@ -180,4 +180,4 @@ POINT (2552089.277631362 6672241.849816945) POINT (2552615.251589643 6672065.289291202) -POINT (2552879.3357571587 6673419.2100551445) \ No newline at end of file +POINT (2552879.3357571587 6673419.2100551445) diff --git a/data/HelsinkiMedium/E_meetingspots.wkt b/data/HelsinkiMedium/E_meetingspots.wkt index 82d0bf105..7bcf94063 100644 --- a/data/HelsinkiMedium/E_meetingspots.wkt +++ b/data/HelsinkiMedium/E_meetingspots.wkt @@ -1,3 +1,3 @@ POINT (2552080.145394281 6673330.999808344) -POINT (2552531.1145652616 6673268.445450311) \ No newline at end of file +POINT (2552531.1145652616 6673268.445450311) diff --git a/data/HelsinkiMedium/E_offices.wkt b/data/HelsinkiMedium/E_offices.wkt index 85ac6c45d..92480d88c 100644 --- a/data/HelsinkiMedium/E_offices.wkt +++ b/data/HelsinkiMedium/E_offices.wkt @@ -40,4 +40,4 @@ POINT (2551923.44544545 6672987.520970024) POINT (2551768.7088863445 6672875.395233927) -POINT (2552330.7745675067 6672982.3197762) \ No newline at end of file +POINT (2552330.7745675067 6672982.3197762) diff --git a/data/HelsinkiMedium/F_bus.wkt b/data/HelsinkiMedium/F_bus.wkt index b4d5e6796..42aae1cf9 100644 --- a/data/HelsinkiMedium/F_bus.wkt +++ b/data/HelsinkiMedium/F_bus.wkt @@ -1,2 +1,2 @@ -LINESTRING (2552951.6016982887 6671978.96947831, 2552883.7245106613 6672239.799346303, 2552821.9107324784 6672739.764102663, 2552599.255738062 6672877.725768852, 2552478.6805102592 6673256.062608091, 2552288.5451893513 6673519.573091362, 2552063.959803357 6673790.795344708, 2551861.5739205102 6674198.388899207, 2551681.816516719 6674680.479552944, 2551335.641209913 6675218.222980602, - 2551083.634364065 6675615.144085466, 2550671.0337880836 6675975.426780757, 2550010.88111605 6676239.047289281, 2549500.1028042943 6676330.738335026, 2548940.256248493 6676559.490840337) \ No newline at end of file +LINESTRING (2552951.6016982887 6671978.96947831, 2552883.7245106613 6672239.799346303, 2552821.9107324784 6672739.764102663, 2552599.255738062 6672877.725768852, 2552478.6805102592 6673256.062608091, 2552288.5451893513 6673519.573091362, 2552063.959803357 6673790.795344708, 2551861.5739205102 6674198.388899207, 2551681.816516719 6674680.479552944, 2551335.641209913 6675218.222980602, + 2551083.634364065 6675615.144085466, 2550671.0337880836 6675975.426780757, 2550010.88111605 6676239.047289281, 2549500.1028042943 6676330.738335026, 2548940.256248493 6676559.490840337) diff --git a/data/HelsinkiMedium/F_homes.wkt b/data/HelsinkiMedium/F_homes.wkt index 2711e7c96..9bab8569f 100644 --- a/data/HelsinkiMedium/F_homes.wkt +++ b/data/HelsinkiMedium/F_homes.wkt @@ -178,4 +178,4 @@ POINT (2548140.6864069286 6676740.502387718) POINT (2548118.3136635106 6677359.964572192) -POINT (2548761.0020664376 6677528.1531763375) \ No newline at end of file +POINT (2548761.0020664376 6677528.1531763375) diff --git a/data/HelsinkiMedium/F_meetingspots.wkt b/data/HelsinkiMedium/F_meetingspots.wkt index 9d271a7dd..5d7fe6990 100644 --- a/data/HelsinkiMedium/F_meetingspots.wkt +++ b/data/HelsinkiMedium/F_meetingspots.wkt @@ -4,4 +4,4 @@ POINT (2552669.1210640236 6673406.247079767) POINT (2550808.454569743 6675266.964168113) -POINT (2550105.5033015246 6676255.961171506) \ No newline at end of file +POINT (2550105.5033015246 6676255.961171506) diff --git a/data/HelsinkiMedium/F_offices.wkt b/data/HelsinkiMedium/F_offices.wkt index ecf8ffb4f..9905454f9 100644 --- a/data/HelsinkiMedium/F_offices.wkt +++ b/data/HelsinkiMedium/F_offices.wkt @@ -56,4 +56,4 @@ POINT (2553381.666543376 6673728.240986674) POINT (2553263.7229177677 6673904.271390739) -POINT (2553841.6277093147 6673119.391238062) \ No newline at end of file +POINT (2553841.6277093147 6673119.391238062) diff --git a/data/HelsinkiMedium/G_bus.wkt b/data/HelsinkiMedium/G_bus.wkt index 8a66b5fe7..6031c6b2d 100644 --- a/data/HelsinkiMedium/G_bus.wkt +++ b/data/HelsinkiMedium/G_bus.wkt @@ -1,2 +1,2 @@ -LINESTRING (2551217.6480870843 6672787.2850100845, 2551825.407951799 6673124.782475507, 2552378.5476342966 6673187.666909302, 2552978.882916019 6673298.132264293, 2552956.9143998967 6673618.665836011, 2552928.601990084 6674017.417361009, 2552890.282892305 6674615.774701311, 2553233.0593900075 6674893.908541065, 2553448.322799578 6675165.300833439, 2553667.3479978647 6675699.133363432, - 2553672.2564721764 6676175.662740696, 2553528.33505563 6676650.701775882, 2553570.820169422 6677006.193371478, 2553044.7884643846 6677290.308584129, 2552610.153375988 6677178.372891653, 2552800.0082126497 6676643.68016422, 2552847.575041023 6676242.638113479) \ No newline at end of file +LINESTRING (2551217.6480870843 6672787.2850100845, 2551825.407951799 6673124.782475507, 2552378.5476342966 6673187.666909302, 2552978.882916019 6673298.132264293, 2552956.9143998967 6673618.665836011, 2552928.601990084 6674017.417361009, 2552890.282892305 6674615.774701311, 2553233.0593900075 6674893.908541065, 2553448.322799578 6675165.300833439, 2553667.3479978647 6675699.133363432, + 2553672.2564721764 6676175.662740696, 2553528.33505563 6676650.701775882, 2553570.820169422 6677006.193371478, 2553044.7884643846 6677290.308584129, 2552610.153375988 6677178.372891653, 2552800.0082126497 6676643.68016422, 2552847.575041023 6676242.638113479) diff --git a/data/HelsinkiMedium/G_homes.wkt b/data/HelsinkiMedium/G_homes.wkt index cc4f87e1d..cd4dc3dc3 100644 --- a/data/HelsinkiMedium/G_homes.wkt +++ b/data/HelsinkiMedium/G_homes.wkt @@ -262,4 +262,4 @@ POINT (2551551.655327319 6676622.915398106) POINT (2551366.758462189 6676642.349858876) -POINT (2552220.610254967 6677124.070427668) \ No newline at end of file +POINT (2552220.610254967 6677124.070427668) diff --git a/data/HelsinkiMedium/G_meetingspots.wkt b/data/HelsinkiMedium/G_meetingspots.wkt index 49ca52af1..d9dbf5086 100644 --- a/data/HelsinkiMedium/G_meetingspots.wkt +++ b/data/HelsinkiMedium/G_meetingspots.wkt @@ -4,4 +4,4 @@ POINT (2552122.746001586 6673002.154328803) POINT (2552677.906820565 6673285.539373861) -POINT (2552459.211603745 6673074.480929848) \ No newline at end of file +POINT (2552459.211603745 6673074.480929848) diff --git a/data/HelsinkiMedium/G_offices.wkt b/data/HelsinkiMedium/G_offices.wkt index b86aa7afe..bba807234 100644 --- a/data/HelsinkiMedium/G_offices.wkt +++ b/data/HelsinkiMedium/G_offices.wkt @@ -56,4 +56,4 @@ POINT (2551364.993061344 6672039.063271573) POINT (2550978.2795313974 6672002.13479542) -POINT (2551001.279239602 6672187.047238169) \ No newline at end of file +POINT (2551001.279239602 6672187.047238169) diff --git a/data/HelsinkiMedium/H_bus.wkt b/data/HelsinkiMedium/H_bus.wkt index 8f99f4b07..ea5198cf3 100644 --- a/data/HelsinkiMedium/H_bus.wkt +++ b/data/HelsinkiMedium/H_bus.wkt @@ -1,2 +1,2 @@ -LINESTRING (2547673.3171570706 6672763.109461098, 2548776.5689421124 6672470.202230424, 2549545.178272597 6672487.866284834, 2550330.047439836 6672702.395525495, 2551005.1565218316 6672769.690971744, 2551733.574109715 6672719.2894031275, 2552249.4588846625 6672531.896391016, 2552747.310172474 6672343.373119477, 2552892.741254229 6673220.99455896, 2553296.217842666 6673446.466311243, - 2552889.0537113426 6673977.008085913, 2552889.218702076 6674644.061193879, 2553352.5456789713 6675010.225239109, 2553526.313919149 6675457.6179286605, 2553675.4737914735 6675736.161862543, 2552982.6364551983 6676025.478269019, 2552089.5251174616 6676457.277379394, 2551257.212864899 6675722.818799925, 2550332.8522822997 6676228.294821279, 2549305.5374822007 6676406.915819961) \ No newline at end of file +LINESTRING (2547673.3171570706 6672763.109461098, 2548776.5689421124 6672470.202230424, 2549545.178272597 6672487.866284834, 2550330.047439836 6672702.395525495, 2551005.1565218316 6672769.690971744, 2551733.574109715 6672719.2894031275, 2552249.4588846625 6672531.896391016, 2552747.310172474 6672343.373119477, 2552892.741254229 6673220.99455896, 2553296.217842666 6673446.466311243, + 2552889.0537113426 6673977.008085913, 2552889.218702076 6674644.061193879, 2553352.5456789713 6675010.225239109, 2553526.313919149 6675457.6179286605, 2553675.4737914735 6675736.161862543, 2552982.6364551983 6676025.478269019, 2552089.5251174616 6676457.277379394, 2551257.212864899 6675722.818799925, 2550332.8522822997 6676228.294821279, 2549305.5374822007 6676406.915819961) diff --git a/data/HelsinkiMedium/roads.wkt b/data/HelsinkiMedium/roads.wkt index 445026b37..e089d2909 100644 --- a/data/HelsinkiMedium/roads.wkt +++ b/data/HelsinkiMedium/roads.wkt @@ -120,7 +120,7 @@ LINESTRING (2552808.4227400413 6675372.088297138, 2552796.3371688365 6675371.648 LINESTRING (2553144.0138913146 6676147.986388173, 2553156.487190742 6676159.188959487) -LINESTRING (2547988.259718087 6672227.376494899, 2547998.5468903002 6672231.24738338, 2548040.3060448663 6672264.735069772, 2548094.447753957 6672319.50764166, 2548124.368823418 6672366.038321796, 2548133.5258091087 6672398.905865847, 2548132.453369343 6672426.1721242415, 2548125.5815053065 6672450.737762765, 2548112.4894906296 6672473.472981155, 2548083.162387808 6672500.249127055, +LINESTRING (2547988.259718087 6672227.376494899, 2547998.5468903002 6672231.24738338, 2548040.3060448663 6672264.735069772, 2548094.447753957 6672319.50764166, 2548124.368823418 6672366.038321796, 2548133.5258091087 6672398.905865847, 2548132.453369343 6672426.1721242415, 2548125.5815053065 6672450.737762765, 2548112.4894906296 6672473.472981155, 2548083.162387808 6672500.249127055, 2548058.529271345 6672511.001595057, 2548002.440671603 6672518.123229678, 2547927.510130133 6672506.360529798) LINESTRING (2552817.3899863893 6675825.142286122, 2552672.198141197 6675830.973624582) @@ -249,7 +249,7 @@ LINESTRING (2551445.1950567393 6673509.880866717, 2551290.1450152406 6673526.754 LINESTRING (2548787.3180883788 6676110.747840851, 2548815.193272748 6676123.740823115, 2548851.441736826 6676140.604693861, 2548909.716463783 6676167.730920114) -LINESTRING (2553505.937563602 6677026.928130704, 2553513.782872964 6677018.266142528, 2553515.969000179 6677009.334092364, 2553513.626131768 6676989.269486957, 2553510.895535134 6676969.885037665, 2553512.0257216557 6676942.078655297, 2553514.7893164367 6676936.40735357, 2553530.3231939645 6676923.54440115, 2553543.2667169822 6676917.793081056, 2553584.448403982 6676899.478877417, +LINESTRING (2553505.937563602 6677026.928130704, 2553513.782872964 6677018.266142528, 2553515.969000179 6677009.334092364, 2553513.626131768 6676989.269486957, 2553510.895535134 6676969.885037665, 2553512.0257216557 6676942.078655297, 2553514.7893164367 6676936.40735357, 2553530.3231939645 6676923.54440115, 2553543.2667169822 6676917.793081056, 2553584.448403982 6676899.478877417, 2553587.4264867157 6676880.294474042) LINESTRING (2552859.4626233485 6674782.643002409, 2552835.0769929853 6674799.846951212, 2552698.3739210153 6674904.100880502) @@ -574,7 +574,7 @@ LINESTRING (2551849.810081235 6674219.603768633, 2551844.6623703605 6674216.3330 LINESTRING (2553505.937563602 6677026.928130704, 2553467.412227406 6677039.220952262, 2553418.81420695 6677066.027105048) -LINESTRING (2551010.510471123 6674129.593108585, 2551015.4271949716 6674107.267984324, 2551014.2392616924 6674078.951484869, 2551005.090525538 6674055.06600246, 2550970.731205355 6674013.506463345, 2550957.655689751 6673913.943610793, 2550959.4458392058 6673875.394762719, 2550972.37286315 6673819.982043899, 2550981.414355328 6673794.056093143, 2551025.4503820115 6673705.495765989, +LINESTRING (2551010.510471123 6674129.593108585, 2551015.4271949716 6674107.267984324, 2551014.2392616924 6674078.951484869, 2551005.090525538 6674055.06600246, 2550970.731205355 6674013.506463345, 2550957.655689751 6673913.943610793, 2550959.4458392058 6673875.394762719, 2550972.37286315 6673819.982043899, 2550981.414355328 6673794.056093143, 2551025.4503820115 6673705.495765989, 2551039.1363633284 6673648.872769374) LINESTRING (2547785.263369528 6677662.604036695, 2547626.23705136 6677528.873341636, 2547565.3719698926 6677523.182035317) @@ -617,7 +617,7 @@ LINESTRING (2550574.0522351246 6672733.982775682, 2550466.775260416 6672725.7608 LINESTRING (2549342.239670795 6671574.806711275, 2549323.9009508025 6671664.947401169) -LINESTRING (2550933.6990352944 6673730.841583586, 2550952.3512376794 6673762.378822294, 2550956.591499522 6673790.235216142, 2550954.025893621 6673808.149327948, 2550946.8735453384 6673823.68289335, 2550935.695423166 6673836.845914644, 2550919.9223090746 6673848.198520395, 2550889.720755367 6673857.050552192, 2550856.8546013194 6673849.638850993, 2550839.654317386 6673838.396270496, +LINESTRING (2550933.6990352944 6673730.841583586, 2550952.3512376794 6673762.378822294, 2550956.591499522 6673790.235216142, 2550954.025893621 6673808.149327948, 2550946.8735453384 6673823.68289335, 2550935.695423166 6673836.845914644, 2550919.9223090746 6673848.198520395, 2550889.720755367 6673857.050552192, 2550856.8546013194 6673849.638850993, 2550839.654317386 6673838.396270496, 2550818.6674961266 6673809.159559825, 2550817.034087868 6673801.027693327) LINESTRING (2547493.01528386 6677618.133829498, 2547492.503812587 6677591.537724922, 2547506.0907994634 6677552.968872257, 2547534.6341963024 6677531.023835236, 2547565.3719698926 6677523.182035317) @@ -648,7 +648,7 @@ LINESTRING (2552243.915196028 6677050.3635098, 2552237.761041681 6677048.7931493 LINESTRING (2552110.0169665217 6675223.784257075, 2552115.544156083 6675204.8399088, 2552129.799355429 6675149.907300179, 2552131.2677729544 6675131.773137865, 2552123.7689441317 6675083.262003157, 2552115.6266514496 6675038.991841876, 2552121.393077574 6674982.378847557, 2552141.422952581 6674921.104783389, 2552161.4693266614 6674891.928086493, 2552177.8116587824 6674881.545703436) -LINESTRING (2549102.912362791 6676997.70142233, 2549086.5535315974 6676993.160380029, 2549076.84382695 6676995.090823121, 2548934.143341829 6677096.614125654, 2548918.2299856143 6677103.31566385, 2548899.899515159 6677105.536173522, 2548817.9156198455 6677099.934887865, 2548806.64675277 6677095.843948876, 2548804.7906070217 6677084.011232926, 2548812.825655727 6677068.397649157, +LINESTRING (2549102.912362791 6676997.70142233, 2549086.5535315974 6676993.160380029, 2549076.84382695 6676995.090823121, 2548934.143341829 6677096.614125654, 2548918.2299856143 6677103.31566385, 2548899.899515159 6677105.536173522, 2548817.9156198455 6677099.934887865, 2548806.64675277 6677095.843948876, 2548804.7906070217 6677084.011232926, 2548812.825655727 6677068.397649157, 2548816.042975024 6677024.077476396) LINESTRING (2549209.8346074237 6675962.77387655, 2549169.8903509225 6676020.817199169, 2549159.636176856 6676030.589442181) @@ -753,7 +753,7 @@ LINESTRING (2552665.84599797 6672078.382296425, 2552615.251589643 6672065.289291 LINESTRING (2553369.1437467285 6674168.962144917, 2553366.421399631 6674205.580549899) -LINESTRING (2552118.0437656906 6673737.923209025, 2552177.8364073923 6673801.157723173, 2552199.0789642883 6673818.001589327, 2552221.748691026 6673826.953644082, 2552240.5658841445 6673806.108859601, 2552297.924912532 6673716.958396994, 2552318.0207838323 6673714.7078804355, 2552341.8371961657 6673705.855848638, 2552354.4919854 6673692.762843415, 2552359.6396962753 6673678.47956499, +LINESTRING (2552118.0437656906 6673737.923209025, 2552177.8364073923 6673801.157723173, 2552199.0789642883 6673818.001589327, 2552221.748691026 6673826.953644082, 2552240.5658841445 6673806.108859601, 2552297.924912532 6673716.958396994, 2552318.0207838323 6673714.7078804355, 2552341.8371961657 6673705.855848638, 2552354.4919854 6673692.762843415, 2552359.6396962753 6673678.47956499, 2552359.0127314893 6673658.444966471) LINESTRING (2552558.552524188 6676065.787521157, 2552502.199939273 6676110.617811005) @@ -800,10 +800,10 @@ LINESTRING (2554142.290322375 6674448.276255577, 2554189.4694225257 6674406.6467 LINESTRING (2553224.2818830027 6677495.7457378935, 2553192.3231779872 6677528.62328424, 2553250.2101767207 6677586.04646452) -LINESTRING (2548102.3838082226 6676803.586867429, 2548035.6450566542 6676890.086721646, 2548013.2558141625 6676917.543023661, 2548002.613911873 6676926.014968216, 2547947.927733363 6676937.697649729, 2547879.547324 6676971.225345305, 2547841.0632354873 6676976.256500101, 2547817.79954211 6676989.749597156, 2547808.3373235622 6677001.832370502, 2547758.4853735343 6677106.116306678, +LINESTRING (2548102.3838082226 6676803.586867429, 2548035.6450566542 6676890.086721646, 2548013.2558141625 6676917.543023661, 2548002.613911873 6676926.014968216, 2547947.927733363 6676937.697649729, 2547879.547324 6676971.225345305, 2547841.0632354873 6676976.256500101, 2547817.79954211 6676989.749597156, 2547808.3373235622 6677001.832370502, 2547758.4853735343 6677106.116306678, 2547743.512464499 6677123.490294511, 2547626.9547610492 6677181.243550552, 2547611.5776247173 6677186.774820139, 2547570.989904357 6677188.935316035) -LINESTRING (2551150.8268401497 6677498.466362355, 2551069.0574327894 6677537.415302263, 2550922.133184899 6677611.7023532875, 2550907.853236943 6677625.3754916685, 2550898.514761445 6677640.66900197, 2550893.301054277 6677658.333056382, 2550893.103065397 6677671.966185579, 2550896.155393961 6677691.5306761945, 2550903.3819880737 6677707.824416079, 2550950.742578031 6677759.3762487145, +LINESTRING (2551150.8268401497 6677498.466362355, 2551069.0574327894 6677537.415302263, 2550922.133184899 6677611.7023532875, 2550907.853236943 6677625.3754916685, 2550898.514761445 6677640.66900197, 2550893.301054277 6677658.333056382, 2550893.103065397 6677671.966185579, 2550896.155393961 6677691.5306761945, 2550903.3819880737 6677707.824416079, 2550950.742578031 6677759.3762487145, 2550958.6786322966 6677784.922112228, 2550960.6090238746 6677807.277243377, 2550962.2424321333 6677826.231593948) LINESTRING (2552952.212164001 6673697.553943111, 2552938.220949828 6673883.426606258) @@ -940,10 +940,10 @@ LINESTRING (2551902.1451417976 6673644.191694933, 2551743.440555559 6673647.4224 LINESTRING (2550848.6793104904 6672658.8755364, 2550854.3137440286 6672591.750129179, 2550611.983604681 6672531.376271633) -LINESTRING (2552559.517719977 6673146.45745054, 2552473.318311431 6673253.912114491, 2552440.104393391 6673297.548247428, 2552408.7574375407 6673338.7315830095, 2552398.0412894213 6673352.814815518, 2552387.0611561285 6673365.997841404, 2552275.9398973365 6673509.820852942, 2552256.454491749 6673534.296470803, 2552195.9111422114 6673612.1843483215, 2552172.432960881 6673639.590638857, - 2552153.657015446 6673654.484057328, 2552149.2847610167 6673657.954853976, 2552146.0756912567 6673660.495437113, 2552144.1535492153 6673662.015786077, 2552140.721741965 6673665.156506963, 2552137.4466759115 6673668.147193412, 2552124.4206575276 6673683.880804731, 2552092.0164775327 6673747.715456628, 2552068.1670670523 6673793.766026565, 2552022.431635817 6673885.937182508, - 2551970.2203183044 6673991.151332197, 2551943.3598269443 6674056.316289438, 2551910.081196063 6674119.950895418, 2551906.723634643 6674125.11208006, 2551861.5739205102 6674198.388899207, 2551849.810081235 6674219.603768633, 2551800.86558024 6674295.731242088, 2551770.499035799 6674351.273990754, 2551761.5729668215 6674388.38925647, 2551760.913074202 6674391.1331395805, - 2551737.2616526014 6674473.952148937, 2551726.108279039 6674513.03111869, 2551681.816516719 6674680.479552944, 2551677.856739123 6674695.442987485, 2551640.0986098363 6674817.1909321565, 2551637.1205271026 6674824.482605807, 2551634.975647571 6674829.743813406, 2551583.8285202878 6674895.818979566, 2551512.1730448706 6674985.079467428, 2551501.1186657483 6674998.4825438205, +LINESTRING (2552559.517719977 6673146.45745054, 2552473.318311431 6673253.912114491, 2552440.104393391 6673297.548247428, 2552408.7574375407 6673338.7315830095, 2552398.0412894213 6673352.814815518, 2552387.0611561285 6673365.997841404, 2552275.9398973365 6673509.820852942, 2552256.454491749 6673534.296470803, 2552195.9111422114 6673612.1843483215, 2552172.432960881 6673639.590638857, + 2552153.657015446 6673654.484057328, 2552149.2847610167 6673657.954853976, 2552146.0756912567 6673660.495437113, 2552144.1535492153 6673662.015786077, 2552140.721741965 6673665.156506963, 2552137.4466759115 6673668.147193412, 2552124.4206575276 6673683.880804731, 2552092.0164775327 6673747.715456628, 2552068.1670670523 6673793.766026565, 2552022.431635817 6673885.937182508, + 2551970.2203183044 6673991.151332197, 2551943.3598269443 6674056.316289438, 2551910.081196063 6674119.950895418, 2551906.723634643 6674125.11208006, 2551861.5739205102 6674198.388899207, 2551849.810081235 6674219.603768633, 2551800.86558024 6674295.731242088, 2551770.499035799 6674351.273990754, 2551761.5729668215 6674388.38925647, 2551760.913074202 6674391.1331395805, + 2551737.2616526014 6674473.952148937, 2551726.108279039 6674513.03111869, 2551681.816516719 6674680.479552944, 2551677.856739123 6674695.442987485, 2551640.0986098363 6674817.1909321565, 2551637.1205271026 6674824.482605807, 2551634.975647571 6674829.743813406, 2551583.8285202878 6674895.818979566, 2551512.1730448706 6674985.079467428, 2551501.1186657483 6674998.4825438205, 2551447.7276644935 6675063.277416117, 2551330.3532569148 6675214.352092121, 2551307.84852091 6675247.109610918, 2551200.670540641 6675403.125421056, 2551140.25918369 6675519.112043337) LINESTRING (2553320.273491563 6674457.528379207, 2553336.030106581 6674451.717045338, 2553487.0213760436 6674460.4490495855, 2553489.306497698 6674471.071487742) @@ -1038,7 +1038,7 @@ LINESTRING (2551229.33768053 6672340.972568481, 2551228.2487416905 6672315.82679 LINESTRING (2553126.3186351815 6676295.190175696, 2553165.0089621106 6676347.372152968) -LINESTRING (2551458.9717829595 6675914.192725771, 2551704.9729661196 6676045.46285606, 2551713.659728221 6676052.784536597, 2551715.8293563626 6676064.487222701, 2551694.933280006 6676090.3431573855, 2551681.618527839 6676127.911780471, 2551633.457732826 6676168.98120709, 2551638.489950188 6676195.097201467, 2551619.318026993 6676238.087068884, 2551592.4327870226 6676276.495884816, +LINESTRING (2551458.9717829595 6675914.192725771, 2551704.9729661196 6676045.46285606, 2551713.659728221 6676052.784536597, 2551715.8293563626 6676064.487222701, 2551694.933280006 6676090.3431573855, 2551681.618527839 6676127.911780471, 2551633.457732826 6676168.98120709, 2551638.489950188 6676195.097201467, 2551619.318026993 6676238.087068884, 2551592.4327870226 6676276.495884816, 2551586.5921150683 6676283.857574537, 2551566.2652567415 6676286.59820359, 2551550.7066306034 6676302.861936587, 2551539.9657338737 6676322.26639047) LINESTRING (2549063.232091463 6676502.957864385, 2549067.1588709126 6676512.280004086) @@ -1151,7 +1151,7 @@ LINESTRING (2552520.4974115817 6672638.460850639, 2552526.3050853894 6672709.167 LINESTRING (2552518.484524637 6672622.867271462, 2552520.4974115817 6672638.460850639) -LINESTRING (2554373.49183677 6675472.6113700885, 2554389.0999601283 6675470.040780064, 2554414.9292594064 6675465.779802047, 2554390.57662719 6675476.172187399, 2554372.8318738374 6675483.753927628, 2554167.1296772542 6675553.870021298, 2554127.870132296 6675559.891403379, 2554104.5899398453 6675563.462222985, 2554060.1661849385 6675561.271720201, 2554008.3260965757 6675547.978669061, +LINESTRING (2554373.49183677 6675472.6113700885, 2554389.0999601283 6675470.040780064, 2554414.9292594064 6675465.779802047, 2554390.57662719 6675476.172187399, 2554372.8318738374 6675483.753927628, 2554167.1296772542 6675553.870021298, 2554127.870132296 6675559.891403379, 2554104.5899398453 6675563.462222985, 2554060.1661849385 6675561.271720201, 2554008.3260965757 6675547.978669061, 2553991.158810789 6675540.406931129) LINESTRING (2551114.611374218 6675220.503504047, 2551061.5256058197 6675212.5716834655) @@ -1248,7 +1248,7 @@ LINESTRING (2553233.0593900075 6674893.908541065, 2553151.1827386706 6674957.583 LINESTRING (2549709.2533072005 6677274.374926895, 2549697.596711902 6677264.142578275, 2549679.752964109 6677240.377123416, 2549675.9251790997 6677233.775608178) -LINESTRING (2549176.6384719093 6674324.00773236, 2549165.8893256434 6674317.4062171215, 2549159.4629365862 6674308.824247311, 2549155.47841038 6674299.692151231, 2549155.7836432364 6674288.779646496, 2549160.5601249617 6674278.587307059, 2549165.608841397 6674274.036262463, 2549171.9527350874 6674274.026260167, 2549187.016389026 6674286.979233249, 2549184.0300567555 6674306.553726161, +LINESTRING (2549176.6384719093 6674324.00773236, 2549165.8893256434 6674317.4062171215, 2549159.4629365862 6674308.824247311, 2549155.47841038 6674299.692151231, 2549155.7836432364 6674288.779646496, 2549160.5601249617 6674278.587307059, 2549165.608841397 6674274.036262463, 2549171.9527350874 6674274.026260167, 2549187.016389026 6674286.979233249, 2549184.0300567555 6674306.553726161, 2549176.6384719093 6674324.00773236) LINESTRING (2551312.9137364184 6673244.529961015, 2551308.689973649 6673268.8555444395, 2551291.341198056 6673494.177262286) @@ -1371,7 +1371,7 @@ LINESTRING (2551658.899303881 6673651.903465007, 2551649.1483515506 6673666.1167 LINESTRING (2552322.863261851 6673626.757693326, 2552317.179331093 6673633.669279735) -LINESTRING (2547371.3676162916 6674760.517924064, 2547369.51972008 6674773.991016528, 2547365.81567812 6674799.196801984, 2547360.288488559 6674811.499625837, 2547352.4926764164 6674819.611487744, 2547331.2088718372 6674825.532846867, 2547266.8707354367 6674835.175060034, 2547250.330414436 6674830.3439511545, 2547207.1523395646 6674787.63414802, 2547189.729318142 6674775.731416, +LINESTRING (2547371.3676162916 6674760.517924064, 2547369.51972008 6674773.991016528, 2547365.81567812 6674799.196801984, 2547360.288488559 6674811.499625837, 2547352.4926764164 6674819.611487744, 2547331.2088718372 6674825.532846867, 2547266.8707354367 6674835.175060034, 2547250.330414436 6674830.3439511545, 2547207.1523395646 6674787.63414802, 2547189.729318142 6674775.731416, 2547154.3718040227 6674762.088284506, 2547129.020977871 6674761.358116913) LINESTRING (2553491.401880009 6676038.891347708, 2553485.651952958 6676036.060697992) @@ -1596,7 +1596,7 @@ LINESTRING (2549314.974952138 6671750.76709927, 2549129.1046416825 6671709.01751 LINESTRING (2553532.6743119126 6673185.456401926, 2553555.352288187 6673221.024565848, 2553557.5136667914 6673231.256914468) -LINESTRING (2551481.427021744 6671124.963459249, 2551445.178557666 6671054.67732655, 2551435.180119236 6671046.105359036, 2551419.3410088513 6671039.603866755, 2551404.846572942 6671040.844151436, 2551386.400608973 6671047.835756212, 2551312.4600119023 6671088.845169057, 2551297.338611207 6671100.237783992, 2551288.8415884483 6671108.17960687, 2551285.1210474153 6671126.433796734, +LINESTRING (2551481.427021744 6671124.963459249, 2551445.178557666 6671054.67732655, 2551435.180119236 6671046.105359036, 2551419.3410088513 6671039.603866755, 2551404.846572942 6671040.844151436, 2551386.400608973 6671047.835756212, 2551312.4600119023 6671088.845169057, 2551297.338611207 6671100.237783992, 2551288.8415884483 6671108.17960687, 2551285.1210474153 6671126.433796734, 2551335.657708986 6671225.196465621, 2551491.2522199047 6671144.017832778) LINESTRING (2552037.8417702955 6673754.316971866, 2551998.169748504 6673877.825320601, 2552022.431635817 6673885.937182508) @@ -1779,7 +1779,7 @@ LINESTRING (2550396.332466888 6677132.652397479, 2550485.9636826837 6677154.5574 LINESTRING (2550692.136102856 6672000.934519922, 2550779.399701631 6671848.84961204) -LINESTRING (2549580.527537179 6675520.572378526, 2549585.370015198 6675542.347376517, 2549589.305044184 6675593.18904615, 2549568.0542377513 6675623.075906048, 2549549.723767296 6675639.769737765, 2549518.738507606 6675693.672109917, 2549495.606806815 6675723.839034098, 2549475.5274345884 6675739.022519146, 2549453.171190243 6675762.447895947, 2549442.5787851736 6675782.422480692, +LINESTRING (2549580.527537179 6675520.572378526, 2549585.370015198 6675542.347376517, 2549589.305044184 6675593.18904615, 2549568.0542377513 6675623.075906048, 2549549.723767296 6675639.769737765, 2549518.738507606 6675693.672109917, 2549495.606806815 6675723.839034098, 2549475.5274345884 6675739.022519146, 2549453.171190243 6675762.447895947, 2549442.5787851736 6675782.422480692, 2549433.677535119 6675822.911774155, 2549389.6992551917 6675872.5131591065, 2549385.1950081764 6675885.236079384, 2549378.3726413595 6675899.999468008) LINESTRING (2551245.6800126503 6674810.619423806, 2551166.9711833904 6674761.498149053) @@ -1798,7 +1798,7 @@ LINESTRING (2549880.1094609373 6676167.43085124, 2549897.6067281906 6676183.1444 LINESTRING (2552715.260722555 6675284.768254665, 2552710.8142222962 6675361.675907194) -LINESTRING (2547920.50627351 6672635.070072358, 2547903.0502539403 6672620.406706692, 2547890.1892262893 6672621.67699826, 2547718.00489715 6672586.118836634, 2547710.035844738 6672587.629183303, 2547706.455545828 6672588.299337123, 2547688.455056839 6672619.506500068, 2547682.754627008 6672635.990283573, 2547679.520808638 6672648.253098243, 2547679.702298444 6672689.502566188, +LINESTRING (2547920.50627351 6672635.070072358, 2547903.0502539403 6672620.406706692, 2547890.1892262893 6672621.67699826, 2547718.00489715 6672586.118836634, 2547710.035844738 6672587.629183303, 2547706.455545828 6672588.299337123, 2547688.455056839 6672619.506500068, 2547682.754627008 6672635.990283573, 2547679.520808638 6672648.253098243, 2547679.702298444 6672689.502566188, 2547676.1549976813 6672704.17593415, 2547665.834827321 6672719.939552356) LINESTRING (2552179.7832980435 6672378.541191566, 2552056.98894488 6672339.2921827845) @@ -2005,12 +2005,12 @@ LINESTRING (2553394.2553363172 6675336.7501860205, 2553372.5013081483 6675350.28 LINESTRING (2547874.358365441 6671779.45368367, 2547987.030537125 6671903.372126534) -LINESTRING (2552565.003661855 6673149.448136989, 2552576.849996497 6673154.089202248, 2552643.456755479 6673204.110683623, 2552681.874847698 6673207.531468792, 2552788.4341127174 6673214.002954185, 2552892.741254229 6673220.99455896, 2552983.1231778613 6673226.425805588, 2552993.2701079515 6673230.756799676, 2553050.2414081157 6673236.108027938, 2553055.265375941 6673247.010530378, - 2553055.669603237 6673293.861283979, 2553119.9004956614 6673301.242978292, 2553205.6544292276 6673309.334835607, 2553290.806146618 6673314.916116672, 2553304.1373978583 6673315.44623835, 2553311.495984558 6673318.586959236, 2553315.5877547404 6673324.248258668, 2553324.134274719 6673336.040965435, 2553344.139401116 6673364.037391424, 2553379.109187012 6673412.298468736, - 2553382.615240092 6673431.512878998, 2553383.2587039513 6673452.957801227, 2553384.355892327 6673489.416169477, 2553390.7657823106 6673499.708531871, 2553398.388354183 6673503.7994708605, 2553399.287553679 6673503.929500706, 2553433.0446576863 6673508.920646318, 2553438.126372268 6673509.670818504, 2553443.909297466 6673513.061596786, 2553451.424625362 6673526.524686954, - 2553479.8277800772 6673656.594541744, 2553493.3322715876 6673718.438736775, 2553545.51884049 6673950.411981339, 2553561.6796828043 6674022.26847448, 2553559.7905389094 6674043.833424259, 2553548.8516533 6674160.680243981, 2553547.647220948 6674163.500891401, 2553538.020011667 6674185.976050099, 2553503.4132053843 6674218.46350691, 2553481.741672582 6674232.366698094, - 2553470.2088203332 6674233.837035579, 2553446.1614209735 6674233.516962113, 2553433.2838942492 6674233.7470149165, 2553381.4190572766 6674234.637219245, 2553366.974118587 6674236.167570504, 2553355.1937802387 6674240.948667904, 2553331.1958780987 6674260.173080462, 2553328.6632703445 6674268.35495844, 2553317.6418893686 6674303.933124657, 2553310.6380327456 6674361.746394473, - 2553308.1714212843 6674396.504372434, 2553303.452686316 6674437.443769208, 2553301.3325553946 6674456.0780463135, 2553296.5148259858 6674498.487780573, 2553292.9180280026 6674525.553993051, 2553290.3854202484 6674548.879346894, 2553291.6228507473 6674559.161706992, 2553292.8767803195 6674569.574096937, 2553318.961815234 6674603.681925669, 2553350.2193096336 6674645.361492335, +LINESTRING (2552565.003661855 6673149.448136989, 2552576.849996497 6673154.089202248, 2552643.456755479 6673204.110683623, 2552681.874847698 6673207.531468792, 2552788.4341127174 6673214.002954185, 2552892.741254229 6673220.99455896, 2552983.1231778613 6673226.425805588, 2552993.2701079515 6673230.756799676, 2553050.2414081157 6673236.108027938, 2553055.265375941 6673247.010530378, + 2553055.669603237 6673293.861283979, 2553119.9004956614 6673301.242978292, 2553205.6544292276 6673309.334835607, 2553290.806146618 6673314.916116672, 2553304.1373978583 6673315.44623835, 2553311.495984558 6673318.586959236, 2553315.5877547404 6673324.248258668, 2553324.134274719 6673336.040965435, 2553344.139401116 6673364.037391424, 2553379.109187012 6673412.298468736, + 2553382.615240092 6673431.512878998, 2553383.2587039513 6673452.957801227, 2553384.355892327 6673489.416169477, 2553390.7657823106 6673499.708531871, 2553398.388354183 6673503.7994708605, 2553399.287553679 6673503.929500706, 2553433.0446576863 6673508.920646318, 2553438.126372268 6673509.670818504, 2553443.909297466 6673513.061596786, 2553451.424625362 6673526.524686954, + 2553479.8277800772 6673656.594541744, 2553493.3322715876 6673718.438736775, 2553545.51884049 6673950.411981339, 2553561.6796828043 6674022.26847448, 2553559.7905389094 6674043.833424259, 2553548.8516533 6674160.680243981, 2553547.647220948 6674163.500891401, 2553538.020011667 6674185.976050099, 2553503.4132053843 6674218.46350691, 2553481.741672582 6674232.366698094, + 2553470.2088203332 6674233.837035579, 2553446.1614209735 6674233.516962113, 2553433.2838942492 6674233.7470149165, 2553381.4190572766 6674234.637219245, 2553366.974118587 6674236.167570504, 2553355.1937802387 6674240.948667904, 2553331.1958780987 6674260.173080462, 2553328.6632703445 6674268.35495844, 2553317.6418893686 6674303.933124657, 2553310.6380327456 6674361.746394473, + 2553308.1714212843 6674396.504372434, 2553303.452686316 6674437.443769208, 2553301.3325553946 6674456.0780463135, 2553296.5148259858 6674498.487780573, 2553292.9180280026 6674525.553993051, 2553290.3854202484 6674548.879346894, 2553291.6228507473 6674559.161706992, 2553292.8767803195 6674569.574096937, 2553318.961815234 6674603.681925669, 2553350.2193096336 6674645.361492335, 2553370.414175374 6674668.426786486, 2553403.107089152 6674705.765356767, 2553423.037969719 6674726.15003564, 2553532.7980549624 6674875.254259368, 2553603.3563420037 6674962.294237559, 2553719.84804916 6675104.546888653, 2553778.3455136064 6675172.792553006, 2553801.2297282973 6675205.690103944, 2553801.5432106904 6675206.240230214) LINESTRING (2549236.2578733414 6676538.766083406, 2549231.959864742 6676574.844364415) @@ -2063,7 +2063,7 @@ LINESTRING (2552938.220949828 6673883.426606258, 2553085.706166211 6673889.87808 LINESTRING (2548872.9647779684 6672919.015245981, 2548857.389652757 6672908.682874403, 2548845.477321822 6672891.298884274, 2548836.732812964 6672864.812804954, 2548834.2249538195 6672841.207386828) -LINESTRING (2551445.7807738422 6677291.28880912, 2551490.7077504853 6677321.915838908, 2551491.862685617 6677333.628527309, 2551488.8103570538 6677348.812012357, 2551479.859609779 6677362.795221908, 2551465.1341868434 6677369.146679751, 2551442.546955472 6677361.174849985, 2551435.048126649 6677367.406280279, 2551429.405443575 6677382.089650537, 2551427.532798753 6677405.685066367, +LINESTRING (2551445.7807738422 6677291.28880912, 2551490.7077504853 6677321.915838908, 2551491.862685617 6677333.628527309, 2551488.8103570538 6677348.812012357, 2551479.859609779 6677362.795221908, 2551465.1341868434 6677369.146679751, 2551442.546955472 6677361.174849985, 2551435.048126649 6677367.406280279, 2551429.405443575 6677382.089650537, 2551427.532798753 6677405.685066367, 2551436.1040673414 6677417.707825937, 2551446.300494652 6677423.239095524) LINESTRING (2552599.255738062 6672877.725768852, 2552579.465099618 6673027.760206092) @@ -2124,7 +2124,7 @@ LINESTRING (2553412.2310766964 6676283.58751255, 2553391.442244317 6676304.27226 LINESTRING (2550335.93760901 6676264.013019638, 2550341.3410555213 6676302.441840163, 2550353.7648577294 6676318.595547906, 2550370.8661472225 6676327.617618732, 2550473.8038656493 6676379.129442184) -LINESTRING (2552087.8834596667 6676362.1955553675, 2552066.946135627 6676364.3160420805, 2552056.9229485868 6676370.257405795, 2552051.288515049 6676379.01941693, 2552029.122010047 6676463.828883153, 2552022.9101089435 6676473.691146828, 2551967.8527012835 6676502.227696791, 2551956.7818230875 6676503.728041164, 2551906.0059249536 6676502.46775189, 2551894.4648231682 6676498.436826677, +LINESTRING (2552087.8834596667 6676362.1955553675, 2552066.946135627 6676364.3160420805, 2552056.9229485868 6676370.257405795, 2552051.288515049 6676379.01941693, 2552029.122010047 6676463.828883153, 2552022.9101089435 6676473.691146828, 2551967.8527012835 6676502.227696791, 2551956.7818230875 6676503.728041164, 2551906.0059249536 6676502.46775189, 2551894.4648231682 6676498.436826677, 2551876.4973323257 6676480.502710278, 2551871.7373496736 6676465.50926885, 2551871.374370061 6676451.686096033, 2551878.0069975345 6676411.426855373, 2551883.7156769023 6676397.683700923, 2551905.6676939507 6676368.146921378) LINESTRING (2552915.658467067 6674300.512339488, 2552992.4286552123 6674304.88334276, 2553005.4134259126 6674311.614887844, 2553009.026722969 6674320.076830104, 2553001.5361436834 6674453.237394302) @@ -2331,7 +2331,7 @@ LINESTRING (2553224.2818830027 6677495.7457378935, 2553284.569496904 6677555.169 LINESTRING (2551230.715353152 6673946.261028575, 2551337.0023834617 6674078.751438953) -LINESTRING (2553293.561491862 6675401.385021583, 2553271.7744655465 6675414.678072723, 2553214.7784167724 6675407.696470243, 2553205.431691738 6675413.437788041, 2553193.997833929 6675415.13817833, 2553184.139637622 6675413.457792633, 2553169.1997267334 6675400.264764451, 2553137.793740674 6675394.893531599, 2553126.500124988 6675385.761435519, 2553121.1296766233 6675372.718441775, +LINESTRING (2553293.561491862 6675401.385021583, 2553271.7744655465 6675414.678072723, 2553214.7784167724 6675407.696470243, 2553205.431691738 6675413.437788041, 2553193.997833929 6675415.13817833, 2553184.139637622 6675413.457792633, 2553169.1997267334 6675400.264764451, 2553137.793740674 6675394.893531599, 2553126.500124988 6675385.761435519, 2553121.1296766233 6675372.718441775, 2553123.942768624 6675325.787669806, 2553131.986066866 6675319.296179822) LINESTRING (2553824.559417968 6675403.835584058, 2553897.2378359307 6675544.497870117) @@ -2514,7 +2514,7 @@ LINESTRING (2553932.14987507 6675424.730380017, 2553933.700787962 6675426.800855 LINESTRING (2549363.721464254 6672660.605933576, 2549366.9222844774 6672680.400476996, 2549410.9500616244 6672715.178459547, 2549456.974226643 6672783.074043546) -LINESTRING (2548760.7710794113 6677439.552839999, 2548739.8750030547 6677437.032261454, 2548728.8866202254 6677437.8524497105, 2548709.2857211246 6677445.674245039, 2548638.4304507636 6677488.664112455, 2548604.7723411964 6677507.0383298695, 2548580.93942979 6677511.469346916, 2548561.817003815 6677519.291142244, 2548484.3786032004 6677568.612462913, 2548468.869474282 6677590.167410396, +LINESTRING (2548760.7710794113 6677439.552839999, 2548739.8750030547 6677437.032261454, 2548728.8866202254 6677437.8524497105, 2548709.2857211246 6677445.674245039, 2548638.4304507636 6677488.664112455, 2548604.7723411964 6677507.0383298695, 2548580.93942979 6677511.469346916, 2548561.817003815 6677519.291142244, 2548484.3786032004 6677568.612462913, 2548468.869474282 6677590.167410396, 2548464.35697773 6677596.738918747) LINESTRING (2550948.0037318603 6675344.031857374, 2550808.454569743 6675266.964168113) @@ -2547,7 +2547,7 @@ LINESTRING (2548287.684900649 6672795.936995965, 2548263.2415235294 6672807.7597 LINESTRING (2553182.3164900206 6674153.00848309, 2553179.3384072864 6674191.97742759) -LINESTRING (2549202.9957415336 6677369.356727963, 2549229.6252458678 6677307.102438805, 2549254.588343797 6677276.985526103, 2549267.127639518 6677269.363776691, 2549260.016538918 6677253.920231951, 2549273.3065424752 6677182.453828346, 2549271.9206203166 6677176.532469223, 2549259.4803190352 6677171.941415444, 2549187.4536144687 6677164.309663736, 2549153.9439965617 6677347.191640435, +LINESTRING (2549202.9957415336 6677369.356727963, 2549229.6252458678 6677307.102438805, 2549254.588343797 6677276.985526103, 2549267.127639518 6677269.363776691, 2549260.016538918 6677253.920231951, 2549273.3065424752 6677182.453828346, 2549271.9206203166 6677176.532469223, 2549259.4803190352 6677171.941415444, 2549187.4536144687 6677164.309663736, 2549153.9439965617 6677347.191640435, 2549202.9957415336 6677369.356727963) LINESTRING (2550252.6502869045 6676539.466244114, 2550329.32148061 6676544.68744253, 2550543.784685124 6676559.450831154) @@ -2614,7 +2614,7 @@ LINESTRING (2552698.3739210153 6674904.100880502, 2552760.872410741 6674986.3297 LINESTRING (2554612.423167014 6675880.555004942, 2554597.4255093685 6675833.024095225, 2554597.260518635 6675818.020651501, 2554621.7368939016 6675740.422840561) -LINESTRING (2548983.7478057574 6674894.218612235, 2548997.4750347575 6674898.389569591, 2549009.428613376 6674897.039259655, 2549031.091896641 6674889.337491877, 2549086.7927681603 6674882.215857256, 2549105.6594584985 6674871.443384662, 2549120.731361974 6674873.913951729, 2549157.8047797177 6674893.198378062, 2549195.595907151 6674905.581220282, 2549232.3640920385 6674913.663075302, +LINESTRING (2548983.7478057574 6674894.218612235, 2548997.4750347575 6674898.389569591, 2549009.428613376 6674897.039259655, 2549031.091896641 6674889.337491877, 2549086.7927681603 6674882.215857256, 2549105.6594584985 6674871.443384662, 2549120.731361974 6674873.913951729, 2549157.8047797177 6674893.198378062, 2549195.595907151 6674905.581220282, 2549232.3640920385 6674913.663075302, 2549285.705596073 6674955.702724616, 2549305.116755831 6674955.132593755, 2549335.5245479546 6674985.489561556) LINESTRING (2551117.853442125 6675055.035524365, 2551105.0584107675 6675048.4140045345, 2551027.08379027 6674989.990594673) @@ -2737,7 +2737,7 @@ LINESTRING (2550933.6990352944 6673730.841583586, 2550817.034087868 6673801.0276 LINESTRING (2553373.384008571 6673347.723646948, 2553377.95425188 6673345.213070698, 2553557.5136667914 6673231.256914468) -LINESTRING (2551906.43490086 6671776.923102828, 2551921.572800629 6671722.220547011, 2551916.697324463 6671708.97750735, 2551897.690392002 6671693.523960315, 2551873.7749852287 6671666.857839669, 2551855.8652411425 6671639.501560613, 2551795.7261189013 6671523.915030164, 2551805.782304088 6671476.494145701, 2551804.5366240526 6671466.011739685, 2551679.473648308 6671222.705893962, +LINESTRING (2551906.43490086 6671776.923102828, 2551921.572800629 6671722.220547011, 2551916.697324463 6671708.97750735, 2551897.690392002 6671693.523960315, 2551873.7749852287 6671666.857839669, 2551855.8652411425 6671639.501560613, 2551795.7261189013 6671523.915030164, 2551805.782304088 6671476.494145701, 2551804.5366240526 6671466.011739685, 2551679.473648308 6671222.705893962, 2551671.422100529 6671215.784305258, 2551660.813196386 6671215.63427082, 2551571.1077347603 6671261.264744333, 2551561.926000459 6671263.085162171, 2551553.84970407 6671260.544579034, 2551547.093333547 6671252.882820439, 2551491.2522199047 6671144.017832778) LINESTRING (2551661.514407002 6673021.638801052, 2551612.3884162 6672988.061093998) @@ -2890,14 +2890,14 @@ LINESTRING (2553672.239973103 6677388.731174959, 2553693.0370550198 6677366.9761 LINESTRING (2553322.5008664606 6675477.422474376, 2553296.729313939 6675472.141262185) -LINESTRING (2552540.7087763953 6673856.620453472, 2552537.656447832 6673859.791181246, 2552526.197841413 6673969.586382417, 2552522.6257920396 6673981.93921775, 2552497.6379455007 6674020.528075008, 2552484.6531748 6674074.850543585, 2552475.850919185 6674149.257622159, 2552457.3059607767 6674203.500072369, 2552433.3163081734 6674251.000975199, 2552457.9659237093 6674315.865863565, +LINESTRING (2552540.7087763953 6673856.620453472, 2552537.656447832 6673859.791181246, 2552526.197841413 6673969.586382417, 2552522.6257920396 6673981.93921775, 2552497.6379455007 6674020.528075008, 2552484.6531748 6674074.850543585, 2552475.850919185 6674149.257622159, 2552457.3059607767 6674203.500072369, 2552433.3163081734 6674251.000975199, 2552457.9659237093 6674315.865863565, 2552469.9772490845 6674314.32551001, 2552538.7948838905 6674256.922334322, 2552572.4117457746 6674236.2575911665, 2552769.740662649 6674190.066989088, 2552873.2723477148 6674175.9337451, 2552913.356846339 6674178.394309871) LINESTRING (2549124.6828900333 6676320.435970336, 2549179.492811593 6676363.095761991) LINESTRING (2552394.7992215143 6671836.756836399, 2552326.2620709543 6671842.438140423, 2552268.0945879743 6671857.091503793, 2552210.3148332173 6671883.367534901, 2552192.6443256945 6671895.100227893) -LINESTRING (2553258.6824508696 6671752.257441346, 2553307.899186575 6671743.005317716, 2553327.4588379925 6671743.275379703, 2553356.2414713944 6671753.047622715, 2553364.416762223 6671759.249046122, 2553372.229073439 6671765.190409836, 2553384.3393932534 6671781.114064775, 2553425.45508396 6671872.695085266, 2553439.4132999866 6671885.367994064, 2553475.3317825985 6671896.300503392, +LINESTRING (2553258.6824508696 6671752.257441346, 2553307.899186575 6671743.005317716, 2553327.4588379925 6671743.275379703, 2553356.2414713944 6671753.047622715, 2553364.416762223 6671759.249046122, 2553372.229073439 6671765.190409836, 2553384.3393932534 6671781.114064775, 2553425.45508396 6671872.695085266, 2553439.4132999866 6671885.367994064, 2553475.3317825985 6671896.300503392, 2553498.7274685623 6671899.161159995, 2553558.3551195306 6671918.175524341, 2553586.8572686864 6671931.4285662975) LINESTRING (2553350.22755917 6673302.153187211, 2553415.7866269965 6673260.363595292, 2553532.6743119126 6673185.456401926) @@ -3060,7 +3060,7 @@ LINESTRING (2554117.6819545226 6673171.423180896, 2554115.636069431 6673175.2140 LINESTRING (2553477.9386361823 6676032.269827878, 2553426.9647491686 6676010.044726576) -LINESTRING (2549341.2497263956 6674960.123739366, 2549344.145313763 6674946.490610169, 2549349.4662649077 6674942.769756126, 2549344.425798009 6674937.468539343, 2549338.9893533513 6674916.443713538, 2549318.283016338 6674889.847608964, 2549302.6088966867 6674852.118949146, 2549295.2750585973 6674810.4193778895, 2549304.605284558 6674782.392945013, 2549319.8504283032 6674725.119799171, +LINESTRING (2549341.2497263956 6674960.123739366, 2549344.145313763 6674946.490610169, 2549349.4662649077 6674942.769756126, 2549344.425798009 6674937.468539343, 2549338.9893533513 6674916.443713538, 2549318.283016338 6674889.847608964, 2549302.6088966867 6674852.118949146, 2549295.2750585973 6674810.4193778895, 2549304.605284558 6674782.392945013, 2549319.8504283032 6674725.119799171, 2549324.709405395 6674705.355262639, 2549331.0615486223 6674700.614174422) LINESTRING (2550305.4720701296 6676712.665998463, 2550341.9845193806 6676750.574699605, 2550362.4351207577 6676788.45339386) @@ -3141,10 +3141,10 @@ LINESTRING (2549247.0812654374 6672845.548383213, 2549207.2030052296 6672804.628 LINESTRING (2553594.125110483 6673282.258620833, 2553609.6342394007 6673306.284135383) -LINESTRING (2549078.5514810383 6677099.384761594, 2549106.962885291 6676998.751663391, 2549127.4134866674 6676931.256171225, 2549142.2461535796 6676882.284930909, 2549199.143207914 6676677.207859796, 2549222.4811471216 6676594.02876779, 2549236.2578733414 6676538.766083406, 2549249.1106514554 6676487.214250771, 2549251.0327934967 6676472.100781793, 2549248.1949528866 6676444.04434203, - 2549248.326945473 6676428.60079729, 2549258.9688477623 6676424.309812385, 2549305.5374822007 6676406.915819961, 2549398.204527487 6676372.2978741415, 2549467.2284007096 6676343.601287446, 2549500.1028042943 6676330.738335026, 2549534.6766124307 6676310.113601054, 2549556.2574003297 6676298.991048107, 2549596.680129957 6676263.692946172, 2549607.06629661 6676254.200767443, - 2549651.97677418 6676213.151345414, 2549716.207666604 6676154.457873566, 2549810.7061090283 6676078.2503817445, 2549830.537995156 6676063.476990825, 2549989.9437920107 6675953.431732257, 2550072.9093821864 6675894.198136435, 2550098.0704689953 6675883.225617925, 2550112.045184095 6675878.084437876, 2550173.908459498 6675874.073517254, 2550230.508530513 6675872.463147627, - 2550277.86912047 6675871.0628262125, 2550369.2079903544 6675868.362206343, 2550494.980426252 6675865.161471682, 2550508.748902935 6675864.831395919, 2550600.854979729 6675862.360828853, 2550689.6034951024 6675859.940273265, 2550769.4590099575 6675857.869798032, 2550821.79407052 6675856.429467434, 2550825.6548536764 6675860.640433973, 2550829.325897489 6675864.911414286, +LINESTRING (2549078.5514810383 6677099.384761594, 2549106.962885291 6676998.751663391, 2549127.4134866674 6676931.256171225, 2549142.2461535796 6676882.284930909, 2549199.143207914 6676677.207859796, 2549222.4811471216 6676594.02876779, 2549236.2578733414 6676538.766083406, 2549249.1106514554 6676487.214250771, 2549251.0327934967 6676472.100781793, 2549248.1949528866 6676444.04434203, + 2549248.326945473 6676428.60079729, 2549258.9688477623 6676424.309812385, 2549305.5374822007 6676406.915819961, 2549398.204527487 6676372.2978741415, 2549467.2284007096 6676343.601287446, 2549500.1028042943 6676330.738335026, 2549534.6766124307 6676310.113601054, 2549556.2574003297 6676298.991048107, 2549596.680129957 6676263.692946172, 2549607.06629661 6676254.200767443, + 2549651.97677418 6676213.151345414, 2549716.207666604 6676154.457873566, 2549810.7061090283 6676078.2503817445, 2549830.537995156 6676063.476990825, 2549989.9437920107 6675953.431732257, 2550072.9093821864 6675894.198136435, 2550098.0704689953 6675883.225617925, 2550112.045184095 6675878.084437876, 2550173.908459498 6675874.073517254, 2550230.508530513 6675872.463147627, + 2550277.86912047 6675871.0628262125, 2550369.2079903544 6675868.362206343, 2550494.980426252 6675865.161471682, 2550508.748902935 6675864.831395919, 2550600.854979729 6675862.360828853, 2550689.6034951024 6675859.940273265, 2550769.4590099575 6675857.869798032, 2550821.79407052 6675856.429467434, 2550825.6548536764 6675860.640433973, 2550829.325897489 6675864.911414286, 2550833.4836639655 6675869.752525461) LINESTRING (2553689.1515232534 6675997.631877468, 2553689.5640000864 6676056.635420486, 2553689.547501013 6676086.742330892) @@ -3375,7 +3375,7 @@ LINESTRING (2552735.637078102 6676535.095240842, 2552785.5550244236 6676634.3080 LINESTRING (2551303.7237525806 6672909.38303511, 2551073.289445095 6672891.4089095285) -LINESTRING (2547582.9599820487 6674466.060337538, 2547514.439330562 6674425.63105785, 2547503.739681516 6674414.138419957, 2547498.682715544 6674402.2756971195, 2547497.618525315 6674376.589801464, 2547529.6019789404 6674324.277794347, 2547535.591142555 6674307.073845543, 2547536.5233401973 6674253.351514716, 2547540.2356316936 6674218.303470177, 2547531.2683853456 6674184.245652923, +LINESTRING (2547582.9599820487 6674466.060337538, 2547514.439330562 6674425.63105785, 2547503.739681516 6674414.138419957, 2547498.682715544 6674402.2756971195, 2547497.618525315 6674376.589801464, 2547529.6019789404 6674324.277794347, 2547535.591142555 6674307.073845543, 2547536.5233401973 6674253.351514716, 2547540.2356316936 6674218.303470177, 2547531.2683853456 6674184.245652923, 2547532.4315700145 6674137.264869476, 2547537.0925582265 6674094.465045679, 2547540.9863395295 6674079.161533081, 2547553.3853931273 6674054.625901445, 2547582.5970024355 6674017.757439067, 2547658.220504985 6673958.333799625, 2547691.1691544 6673914.113649822, 2547700.161149358 6673908.902453702, 2547741.219093308 6673902.38095683) LINESTRING (2553203.32805989 6675312.814692133, 2553241.9111428424 6675316.725589797) @@ -3566,7 +3566,7 @@ LINESTRING (2552733.706686524 6674363.156718183, 2552629.5150385257 6674398.8349 LINESTRING (2547830.4048341243 6672948.171938284, 2547782.706013164 6673175.964223197, 2547776.2631250336 6673220.1143569285, 2547776.114633374 6673256.982819306, 2547781.8480613516 6673283.718956022) -LINESTRING (2550674.9523179964 6674116.500103362, 2550664.4836559766 6674113.329375588, 2550650.0139686773 6674100.476425465, 2550640.1475228337 6674080.841918779, 2550633.943871266 6674042.0630179, 2550645.8562022015 6673991.161334492, 2550645.410727222 6673981.349082297, 2550637.8129039593 6673962.314713359, 2550616.265114207 6673944.200555637, 2550609.1292649973 6673933.918195537, +LINESTRING (2550674.9523179964 6674116.500103362, 2550664.4836559766 6674113.329375588, 2550650.0139686773 6674100.476425465, 2550640.1475228337 6674080.841918779, 2550633.943871266 6674042.0630179, 2550645.8562022015 6673991.161334492, 2550645.410727222 6673981.349082297, 2550637.8129039593 6673962.314713359, 2550616.265114207 6673944.200555637, 2550609.1292649973 6673933.918195537, 2550602.87611621 6673919.264832167, 2550599.832037183 6673900.880612458, 2550603.0493564797 6673873.6943724295, 2550611.1504014786 6673856.980536122) LINESTRING (2553001.2886575833 6672957.1539999265, 2552994.8622685266 6673053.926211947) @@ -3687,7 +3687,7 @@ LINESTRING (2554689.003615816 6675483.063769217, 2554673.997708634 6675411.23728 LINESTRING (2553210.7361438093 6675702.444123347, 2553255.448632499 6675777.9514544625, 2553136.3335726853 6675843.806570115, 2553036.877158729 6675914.892886478) -LINESTRING (2551999.085447073 6675223.374162947, 2551999.836154909 6675231.335990416, 2552005.198353737 6675330.548762615, 2552011.3030108646 6675365.086690067, 2552030.169701203 6675410.377085522, 2552054.712072762 6675461.248762041, 2552048.7806559047 6675498.237251969, 2551956.270351815 6675854.0589233255, 2551924.6168796555 6675975.806867997, 2551878.3452285375 6676036.390773755, +LINESTRING (2551999.085447073 6675223.374162947, 2551999.836154909 6675231.335990416, 2552005.198353737 6675330.548762615, 2552011.3030108646 6675365.086690067, 2552030.169701203 6675410.377085522, 2552054.712072762 6675461.248762041, 2552048.7806559047 6675498.237251969, 2551956.270351815 6675854.0589233255, 2551924.6168796555 6675975.806867997, 2551878.3452285375 6676036.390773755, 2551873.568746812 6676050.864095801) LINESTRING (2551433.3982193177 6673228.386255568, 2551424.051494283 6673230.496739985) @@ -3720,7 +3720,7 @@ LINESTRING (2552932.009048724 6672051.656162005, 2552909.710551136 6672140.62658 LINESTRING (2553248.6180161457 6676044.322594336, 2553284.1240219246 6676080.130813357) -LINESTRING (2554628.592258865 6675609.082694202, 2554618.8495560708 6675592.478883147, 2554608.5623838576 6675549.84909838, 2554616.7129260763 6675534.875661543, 2554630.959875886 6675521.212525458, 2554637.8564885324 6675500.547782303, 2554633.59147808 6675465.359705622, 2554623.0238216203 6675421.849718823, 2554615.458996504 6675390.722574243, 2554594.686663198 6675384.011033751, +LINESTRING (2554628.592258865 6675609.082694202, 2554618.8495560708 6675592.478883147, 2554608.5623838576 6675549.84909838, 2554616.7129260763 6675534.875661543, 2554630.959875886 6675521.212525458, 2554637.8564885324 6675500.547782303, 2554633.59147808 6675465.359705622, 2554623.0238216203 6675421.849718823, 2554615.458996504 6675390.722574243, 2554594.686663198 6675384.011033751, 2554435.9490788123 6675418.588970386, 2554418.1960759233 6675429.631504968, 2554413.4278437346 6675436.513084489, 2554417.3463736475 6675464.429492111, 2554417.577360674 6675465.189666593, 2554433.705204841 6675518.5819216585, 2554453.2236085758 6675553.930035072) LINESTRING (2551832.205570006 6673236.458108292, 2551686.7332405676 6673273.27655919) @@ -3737,7 +3737,7 @@ LINESTRING (2552498.4628991666 6676774.4501797175, 2552471.6106573427 6676767.93 LINESTRING (2554429.1597101423 6676121.850389206, 2554406.572478771 6676113.638504341, 2554385.791895928 6676101.185646051, 2554362.7756886506 6676066.617711711, 2554376.2801801604 6676032.549892161, 2554377.773346296 6676022.447573387, 2554374.828261709 6676016.516211968, 2554346.812835216 6675966.984843087) -LINESTRING (2547873.426167799 6672736.283303719, 2547884.785779778 6672749.516341084, 2547916.3072593505 6672756.8680285085, 2547939.174974968 6672759.738687407, 2547955.566804309 6672757.418154778, 2547968.4113328867 6672749.226274505, 2547975.844165416 6672737.33354478, 2547977.477573674 6672724.620626798, 2547974.3839974273 6672712.217779986, 2547968.3123384467 6672704.125922671, +LINESTRING (2547873.426167799 6672736.283303719, 2547884.785779778 6672749.516341084, 2547916.3072593505 6672756.8680285085, 2547939.174974968 6672759.738687407, 2547955.566804309 6672757.418154778, 2547968.4113328867 6672749.226274505, 2547975.844165416 6672737.33354478, 2547977.477573674 6672724.620626798, 2547974.3839974273 6672712.217779986, 2547968.3123384467 6672704.125922671, 2547948.818683322 6672694.033606193, 2547920.7125119264 6672681.830805297) LINESTRING (2550948.0037318603 6675344.031857374, 2550915.244821789 6675393.543221664) @@ -3962,10 +3962,10 @@ LINESTRING (2552925.557911057 6674460.349026627, 2552918.4798086043 6674594.7698 LINESTRING (2552103.912309394 6674035.331472816, 2552084.14641956 6674019.7879051175) -LINESTRING (2554412.3554039686 6675566.242861222, 2554390.57662719 6675476.172187399, 2554389.0999601283 6675470.040780064, 2554388.472995342 6675467.460187743, 2554379.431503164 6675430.071605983, 2554375.158243175 6675410.9972278625, 2554288.1503800363 6675429.891564659, 2554273.8456834704 6675439.653805375, 2554238.446921668 6675479.002837115, 2554207.3379189284 6675494.726446138, - 2554173.8860477777 6675504.448677671, 2554079.6020933064 6675514.631014812, 2554042.000705216 6675510.840144698, 2554007.4763943 6675496.876939738, 2553978.9164983877 6675474.841882056, 2553933.700787962 6675426.800855252, 2553991.158810789 6675540.406931129, 2554008.458089162 6675550.689291228, 2554046.6369448183 6675568.053276764, 2554062.0553288334 6675571.724119329, - 2554093.4943130394 6675575.6750261765, 2554099.6319683134 6675575.384959597, 2554162.3449459923 6675572.354263965, 2554200.2515669386 6675562.872087532, 2554275.4873412657 6675529.864511339, 2554327.5254185083 6675517.011561216, 2554364.772076522 6675514.701030882, 2554378.4168101554 6675519.092038745, 2554390.2218971136 6675529.964534298, 2554412.3554039686 6675566.242861222, - 2554425.736152429 6675609.322749301, 2554468.641992591 6675824.642171331, 2554480.909053602 6675905.650765144, 2554476.825532956 6675953.481743736, 2554451.334464681 6676058.205780929, 2554429.1597101423 6676121.850389206, 2554414.8467640397 6676158.238741385, 2554379.8934772173 6676217.332305065, 2554291.7966752397 6676321.246156297, 2554048.9550646194 6676589.457718601, +LINESTRING (2554412.3554039686 6675566.242861222, 2554390.57662719 6675476.172187399, 2554389.0999601283 6675470.040780064, 2554388.472995342 6675467.460187743, 2554379.431503164 6675430.071605983, 2554375.158243175 6675410.9972278625, 2554288.1503800363 6675429.891564659, 2554273.8456834704 6675439.653805375, 2554238.446921668 6675479.002837115, 2554207.3379189284 6675494.726446138, + 2554173.8860477777 6675504.448677671, 2554079.6020933064 6675514.631014812, 2554042.000705216 6675510.840144698, 2554007.4763943 6675496.876939738, 2553978.9164983877 6675474.841882056, 2553933.700787962 6675426.800855252, 2553991.158810789 6675540.406931129, 2554008.458089162 6675550.689291228, 2554046.6369448183 6675568.053276764, 2554062.0553288334 6675571.724119329, + 2554093.4943130394 6675575.6750261765, 2554099.6319683134 6675575.384959597, 2554162.3449459923 6675572.354263965, 2554200.2515669386 6675562.872087532, 2554275.4873412657 6675529.864511339, 2554327.5254185083 6675517.011561216, 2554364.772076522 6675514.701030882, 2554378.4168101554 6675519.092038745, 2554390.2218971136 6675529.964534298, 2554412.3554039686 6675566.242861222, + 2554425.736152429 6675609.322749301, 2554468.641992591 6675824.642171331, 2554480.909053602 6675905.650765144, 2554476.825532956 6675953.481743736, 2554451.334464681 6676058.205780929, 2554429.1597101423 6676121.850389206, 2554414.8467640397 6676158.238741385, 2554379.8934772173 6676217.332305065, 2554291.7966752397 6676321.246156297, 2554048.9550646194 6676589.457718601, 2553915.7250475828 6676736.621496942, 2553857.3925738693 6676805.917402355, 2553716.66372801 6676949.040253185, 2553701.558826388 6676964.403779559) LINESTRING (2551050.380481794 6676014.395725255, 2551042.279436795 6676028.979072555) @@ -4028,7 +4028,7 @@ LINESTRING (2552883.7245106613 6672239.799346303, 2552708.001130296 6672220.4849 LINESTRING (2547919.3513383777 6672037.772975412, 2547917.4126972626 6672072.730999289, 2547919.3348393044 6672089.184775907, 2547941.9715678957 6672164.342026668, 2548008.8175634407 6672181.105874455) -LINESTRING (2547822.9555025217 6675118.270038513, 2547815.8774000686 6675135.994106699, 2547787.639236086 6675171.432240775, 2547832.689955779 6675216.082489297, 2547969.0712958192 6675331.919077141, 2547992.9702035193 6675351.2235080665, 2548071.4397962163 6675384.621173795, 2548114.2713905475 6675401.815120303, 2548130.036255102 6675412.527579122, 2548133.360818376 6675415.518265571, +LINESTRING (2547822.9555025217 6675118.270038513, 2547815.8774000686 6675135.994106699, 2547787.639236086 6675171.432240775, 2547832.689955779 6675216.082489297, 2547969.0712958192 6675331.919077141, 2547992.9702035193 6675351.2235080665, 2548071.4397962163 6675384.621173795, 2548114.2713905475 6675401.815120303, 2548130.036255102 6675412.527579122, 2548133.360818376 6675415.518265571, 2548161.7639730913 6675445.2650933275, 2548197.1462358204 6675461.698865353, 2548265.4029021338 6675448.585855539, 2548284.533577645 6675458.298084776, 2548320.2128236936 6675473.841652474, 2548327.4889150267 6675467.790263506, 2548394.1946684485 6675373.758680539) LINESTRING (2548937.352411589 6676552.259180462, 2548815.5315037514 6676605.441387315, 2548768.484396187 6676625.876077668) @@ -4125,7 +4125,7 @@ LINESTRING (2550574.0522351246 6672733.982775682, 2550591.8217370873 6672639.351 LINESTRING (2552416.008780264 6676004.983564893, 2552350.466211511 6676058.945950819) -LINESTRING (2550305.4720701296 6676712.665998463, 2550319.603526426 6676708.114953866, 2550358.986814434 6676710.765562258, 2550374.264956326 6676708.565057178, 2550419.4311695322 6676691.251083121, 2550483.3073318796 6676692.771432085, 2550494.8319345918 6676690.410890272, 2550508.2044335157 6676682.489071986, 2550520.0507681575 6676671.396525926, 2550528.589038599 6676657.773399024, +LINESTRING (2550305.4720701296 6676712.665998463, 2550319.603526426 6676708.114953866, 2550358.986814434 6676710.765562258, 2550374.264956326 6676708.565057178, 2550419.4311695322 6676691.251083121, 2550483.3073318796 6676692.771432085, 2550494.8319345918 6676690.410890272, 2550508.2044335157 6676682.489071986, 2550520.0507681575 6676671.396525926, 2550528.589038599 6676657.773399024, 2550535.328910049 6676638.418956621, 2550543.784685124 6676559.450831154) LINESTRING (2552706.5574613805 6672882.976974156, 2552692.5414985977 6673061.627979725) @@ -4186,7 +4186,7 @@ LINESTRING (2550945.1988893966 6672062.238590978, 2550905.988841658 6672124.8129 LINESTRING (2551820.4664793406 6674029.830210117, 2551774.252574979 6674172.703003552) -LINESTRING (2552103.912309394 6674035.331472816, 2552115.816390793 6674056.896422595, 2552118.159259204 6674071.259719387, 2552103.541080245 6674163.490889105, 2552103.6483242214 6674198.088830333, 2552109.596240152 6674212.962244211, 2552214.6540894997 6674348.383327263, 2552243.164488192 6674399.625088728, 2552256.8504695087 6674439.934340866, 2552263.9120728886 6674476.642766511, +LINESTRING (2552103.912309394 6674035.331472816, 2552115.816390793 6674056.896422595, 2552118.159259204 6674071.259719387, 2552103.541080245 6674163.490889105, 2552103.6483242214 6674198.088830333, 2552109.596240152 6674212.962244211, 2552214.6540894997 6674348.383327263, 2552243.164488192 6674399.625088728, 2552256.8504695087 6674439.934340866, 2552263.9120728886 6674476.642766511, 2552262.1714206534 6674516.3718854925, 2552255.5717913266 6674537.866819201) LINESTRING (2549176.6384719093 6674324.00773236, 2549204.851887282 6674370.64843775, 2549202.0552943544 6674387.532313087, 2549178.5936120977 6674436.473546514, 2549162.54001376 6674500.83832009) @@ -4257,10 +4257,10 @@ LINESTRING (2547742.1430414137 6672483.21521728, 2547716.033257889 6672484.28546 LINESTRING (2549757.9255734864 6677481.262413552, 2549744.9490523227 6677469.449702193, 2549739.232123418 6677456.1766556455, 2549751.8044172856 6677393.642302204) -LINESTRING (2553787.7499853973 6675169.691841302, 2553923.867340265 6675169.641829823, 2553945.72861241 6675174.152865237, 2553962.425674607 6675185.365438846, 2554002.2709366684 6675228.945441716, 2554011.444421433 6675235.837023534, 2554028.2899752897 6675236.907269185, 2554040.1528090048 6675232.85633938, 2554053.7892931015 6675222.083866786, 2554176.6496425583 6675114.949276302, +LINESTRING (2553787.7499853973 6675169.691841302, 2553923.867340265 6675169.641829823, 2553945.72861241 6675174.152865237, 2553962.425674607 6675185.365438846, 2554002.2709366684 6675228.945441716, 2554011.444421433 6675235.837023534, 2554028.2899752897 6675236.907269185, 2554040.1528090048 6675232.85633938, 2554053.7892931015 6675222.083866786, 2554176.6496425583 6675114.949276302, 2554188.5454744203 6675108.357763359, 2554212.931104783 6675112.068615107, 2554239.172880894 6675133.953638352) -LINESTRING (2548472.3342796788 6677228.03429038, 2548452.221909305 6677348.741996286, 2548434.0894277296 6677375.8282133555, 2548419.2485112804 6677386.240603301, 2548391.010347298 6677396.202889933, 2548355.471343373 6677398.4334019, 2548342.2885837923 6677396.432942737, 2548319.7343505677 6677381.069416364, 2548311.2785754926 6677367.286252729, 2548308.6634723716 6677355.553559737, +LINESTRING (2548472.3342796788 6677228.03429038, 2548452.221909305 6677348.741996286, 2548434.0894277296 6677375.8282133555, 2548419.2485112804 6677386.240603301, 2548391.010347298 6677396.202889933, 2548355.471343373 6677398.4334019, 2548342.2885837923 6677396.432942737, 2548319.7343505677 6677381.069416364, 2548311.2785754926 6677367.286252729, 2548308.6634723716 6677355.553559737, 2548305.462652148 6677327.097028141, 2548293.6328165797 6677280.036226327) LINESTRING (2553240.327231804 6672440.575430216, 2553257.577012957 6672503.50987549, 2553265.8842963725 6672521.714053876) @@ -4289,7 +4289,7 @@ LINESTRING (2551760.913074202 6674391.1331395805, 2551754.717672171 6674389.8428 LINESTRING (2553209.226478601 6675582.396568964, 2553052.246045524 6675578.855756246) -LINESTRING (2554288.274123086 6677394.042394036, 2554323.4088997156 6677433.221386747, 2554345.5671551805 6677468.3994611325, 2554369.5898059304 6677532.834250779, 2554377.0968842898 6677580.555204117, 2554376.148187574 6677595.79870294, 2554366.7519653197 6677629.8965293765, 2554365.0195626216 6677647.730622817, 2554367.7749078656 6677663.394218065, 2554428.00477501 6677820.860361095, +LINESTRING (2554288.274123086 6677394.042394036, 2554323.4088997156 6677433.221386747, 2554345.5671551805 6677468.3994611325, 2554369.5898059304 6677532.834250779, 2554377.0968842898 6677580.555204117, 2554376.148187574 6677595.79870294, 2554366.7519653197 6677629.8965293765, 2554365.0195626216 6677647.730622817, 2554367.7749078656 6677663.394218065, 2554428.00477501 6677820.860361095, 2554430.0754087116 6677849.676975341) LINESTRING (2553517.874643147 6675334.66970849, 2553526.3386677587 6675339.550828849, 2553746.7085405206 6675232.42624066, 2553788.31095389 6675212.56168117) @@ -4430,7 +4430,7 @@ LINESTRING (2547582.9599820487 6674466.060337538, 2547591.2012691707 6674453.197 LINESTRING (2553530.776918481 6676863.170543605, 2553536.576342752 6676888.54636809, 2553543.2667169822 6676917.793081056, 2553551.4997545676 6676953.7513345145, 2553570.820169422 6677006.193371478, 2553580.340134726 6677032.019299274) -LINESTRING (2551757.291527609 6676327.267538378, 2551753.7442268454 6676516.801041795, 2551746.872362809 6676550.868861344, 2551731.693215357 6676588.177424737, 2551726.999228998 6676599.710071813, 2551691.509722293 6676652.712237342, 2551682.9632023145 6676821.631009081, 2551662.3063625214 6676893.987617014, 2551653.61960042 6676966.014149185, 2551637.326765519 6677060.915931887, +LINESTRING (2551757.291527609 6676327.267538378, 2551753.7442268454 6676516.801041795, 2551746.872362809 6676550.868861344, 2551731.693215357 6676588.177424737, 2551726.999228998 6676599.710071813, 2551691.509722293 6676652.712237342, 2551682.9632023145 6676821.631009081, 2551662.3063625214 6676893.987617014, 2551653.61960042 6676966.014149185, 2551637.326765519 6677060.915931887, 2551629.761940403 6677082.770948244, 2551584.183250364 6677169.180781798) LINESTRING (2553485.148731222 6673735.572669507, 2553381.666543376 6673728.240986674) @@ -4441,7 +4441,7 @@ LINESTRING (2553302.165758597 6672544.049180432, 2553306.0677894363 6672556.5020 LINESTRING (2551230.715353152 6673946.261028575, 2551201.2315091337 6673936.978898058) -LINESTRING (2552554.469003542 6673143.706819191, 2552508.7708714856 6673110.496865532, 2552459.211603745 6673074.480929848, 2552330.7745675067 6672982.3197762, 2552261.900555275 6672932.613958296, 2552203.5997103774 6672890.538709792, 2552065.320976905 6672790.54575852, 2551986.7936374517 6672734.5429042475, 2551898.243110958 6672671.248376324, 2551824.970726356 6672617.436024834, +LINESTRING (2552554.469003542 6673143.706819191, 2552508.7708714856 6673110.496865532, 2552459.211603745 6673074.480929848, 2552330.7745675067 6672982.3197762, 2552261.900555275 6672932.613958296, 2552203.5997103774 6672890.538709792, 2552065.320976905 6672790.54575852, 2551986.7936374517 6672734.5429042475, 2551898.243110958 6672671.248376324, 2551824.970726356 6672617.436024834, 2551800.230365917 6672605.523290517, 2551795.8003647313 6672629.388768334, 2551790.0999349 6672641.201479693, 2551733.574109715 6672719.2894031275, 2551619.8624964124 6672639.221025121, 2551531.089232429 6672581.677817292, 2551522.3364740345 6672575.816471944, 2551503.8905100655 6672563.463636612, 2551487.9111575577 6672562.0333083095) LINESTRING (2551273.0354762105 6676879.604315631, 2551260.479681416 6676899.398859051, 2551251.314446188 6676921.94403382) @@ -4766,7 +4766,7 @@ LINESTRING (2553932.7438417096 6677359.32442526, 2553875.4425600786 6677416.4275 LINESTRING (2548826.3961435305 6676796.665278725, 2548822.997334427 6676901.8294169335, 2548791.005631265 6676900.409090928, 2548780.256484999 6676907.05061535, 2548654.855278251 6677031.539189075) -LINESTRING (2553636.857710374 6677136.563295143, 2553601.5909411586 6677123.940397823, 2553575.456409024 6677123.720347315, 2553552.7619336764 6677113.357968849, 2553538.242749157 6677080.780491377, 2553519.7555375053 6677022.507115954, 2553570.820169422 6677006.193371478, 2553701.558826388 6676964.403779559, 2553684.4162892113 6676981.82777887, 2553659.279951012 6676995.380889701, +LINESTRING (2553636.857710374 6677136.563295143, 2553601.5909411586 6677123.940397823, 2553575.456409024 6677123.720347315, 2553552.7619336764 6677113.357968849, 2553538.242749157 6677080.780491377, 2553519.7555375053 6677022.507115954, 2553570.820169422 6677006.193371478, 2553701.558826388 6676964.403779559, 2553684.4162892113 6676981.82777887, 2553659.279951012 6676995.380889701, 2553649.0092778723 6677005.473206178, 2553633.293910538 6677032.589430136, 2553627.568732097 6677051.813842694, 2553626.4962923313 6677070.998246069, 2553628.2286950294 6677094.623668786, 2553630.315827804 6677124.7905929675) LINESTRING (2549184.987003008 6672841.267400604, 2549145.2159867766 6672828.484466551) @@ -4839,7 +4839,7 @@ LINESTRING (2551374.3892835984 6672043.314247294, 2551364.5310872914 6671947.522 LINESTRING (2553096.81829209 6676021.077258861, 2553171.336356728 6675959.843203875, 2553183.3311830293 6675952.131433801, 2553201.7441488514 6675946.3501068195) -LINESTRING (2551800.230365917 6672605.523290517, 2551785.174961515 6672603.022716563, 2551761.795774624 6672609.224139969, 2551737.7731238743 6672604.973164247, 2551675.596366078 6672560.723007558, 2551609.583573736 6672512.792006007, 2551592.7710180255 6672511.671748877, 2551562.9076953214 6672521.093911535, 2551507.050082606 6672544.609308998, 2551487.9111575577 6672562.0333083095, +LINESTRING (2551800.230365917 6672605.523290517, 2551785.174961515 6672603.022716563, 2551761.795774624 6672609.224139969, 2551737.7731238743 6672604.973164247, 2551675.596366078 6672560.723007558, 2551609.583573736 6672512.792006007, 2551592.7710180255 6672511.671748877, 2551562.9076953214 6672521.093911535, 2551507.050082606 6672544.609308998, 2551487.9111575577 6672562.0333083095, 2551420.1329643703 6672640.221254703, 2551414.6140243458 6672657.84529993, 2551395.013125245 6672698.214565843, 2551382.737814697 6672714.818376898, 2551364.7703238544 6672731.342169586, 2551332.7043748624 6672762.019210854, 2551326.104745535 6672791.0058641285, 2551317.2612422374 6672889.818544494) LINESTRING (2551519.869862573 6672942.42061819, 2551428.9187209117 6672931.848191513) @@ -5322,7 +5322,7 @@ LINESTRING (2548275.4590873206 6676549.548558296, 2548318.8434006083 6676596.559 LINESTRING (2554280.189577161 6673075.421145655, 2554266.635588431 6673100.146820912) -LINESTRING (2551912.597304744 6677299.730746788, 2551917.1592985163 6677415.157240504, 2551924.130156993 6677482.70274415, 2551938.0141271893 6677573.793652145, 2551941.0829548263 6677586.416549465, 2551947.6495860065 6677613.392741281, 2551956.550836061 6677631.126811762, 2551968.199181823 6677649.330990147, 2551983.5680686184 6677661.813855326, 2551999.8279053723 6677670.175774627, +LINESTRING (2551912.597304744 6677299.730746788, 2551917.1592985163 6677415.157240504, 2551924.130156993 6677482.70274415, 2551938.0141271893 6677573.793652145, 2551941.0829548263 6677586.416549465, 2551947.6495860065 6677613.392741281, 2551956.550836061 6677631.126811762, 2551968.199181823 6677649.330990147, 2551983.5680686184 6677661.813855326, 2551999.8279053723 6677670.175774627, 2552016.566215253 6677675.446984523, 2552033.717001966 6677679.347879891, 2552054.5470820293 6677678.557698522, 2552090.440816031 6677666.6749710925, 2552102.732625652 6677655.452395187, 2552123.009986759 6677628.6462424, 2552136.176247266 6677605.070831162) LINESTRING (2546952.1096642264 6672967.336337067, 2547052.3002869454 6672935.599052443) @@ -5855,33 +5855,33 @@ LINESTRING (2552089.5251174616 6676457.277379394, 2552060.3300072267 6676568.232 LINESTRING (2552609.3944186154 6675551.299431273, 2552627.8981293407 6675578.555687371, 2552679.7877149233 6675641.640167083) -LINESTRING (2549044.6953825913 6677254.21029853, 2549022.611372956 6677239.146841031, 2549005.5925788293 6677219.95243536, 2548989.3492411487 6677203.238599052, 2548967.37247549 6677184.804367863, 2548950.23818785 6677173.841851649, 2548923.212705756 6677162.749305589, 2548895.25502602 6677159.888648985, 2548853.2071376713 6677163.419459408, 2548816.1007217807 6677167.030288198, - 2548774.3415672146 6677162.519252785, 2548855.731495889 6677158.098238034, 2548923.121960853 6677157.91819671, 2548967.8179504694 6677161.789085191, 2549061.2027054452 6677165.359904797, 2549078.5514810383 6677099.384761594, 2549060.1137666064 6677088.8123349175, 2549031.2816359843 6677090.07262419, 2548983.393075681 6677098.46455038, 2548942.013399801 6677113.54801247, - 2548906.3671518993 6677130.371874033, 2548854.2465792904 6677147.775868752, 2548774.3415672146 6677162.519252785, 2548621.5271501504 6677157.598123243, 2548561.2972830054 6677146.435561113, 2548245.7607553494 6677087.942135181, 2548227.554027944 6677086.711852795, 2548071.703781389 6677086.111715047, 2547917.338451433 6677110.957417854, 2547839.223588812 6677132.572379112, +LINESTRING (2549044.6953825913 6677254.21029853, 2549022.611372956 6677239.146841031, 2549005.5925788293 6677219.95243536, 2548989.3492411487 6677203.238599052, 2548967.37247549 6677184.804367863, 2548950.23818785 6677173.841851649, 2548923.212705756 6677162.749305589, 2548895.25502602 6677159.888648985, 2548853.2071376713 6677163.419459408, 2548816.1007217807 6677167.030288198, + 2548774.3415672146 6677162.519252785, 2548855.731495889 6677158.098238034, 2548923.121960853 6677157.91819671, 2548967.8179504694 6677161.789085191, 2549061.2027054452 6677165.359904797, 2549078.5514810383 6677099.384761594, 2549060.1137666064 6677088.8123349175, 2549031.2816359843 6677090.07262419, 2548983.393075681 6677098.46455038, 2548942.013399801 6677113.54801247, + 2548906.3671518993 6677130.371874033, 2548854.2465792904 6677147.775868752, 2548774.3415672146 6677162.519252785, 2548621.5271501504 6677157.598123243, 2548561.2972830054 6677146.435561113, 2548245.7607553494 6677087.942135181, 2548227.554027944 6677086.711852795, 2548071.703781389 6677086.111715047, 2547917.338451433 6677110.957417854, 2547839.223588812 6677132.572379112, 2547608.5335456906 6677220.122474389, 2547152.6888985443 6677394.032391741, 2547130.3904009564 6677402.35430186, 2547035.0257571824 6677437.392344103, 2546989.15833336 6677455.196430655, 2546745.0545436316 6677547.607641699) -LINESTRING (2551018.1247934587 6672888.988353942, 2551072.6047335523 6672871.274288051, 2551102.270067377 6672869.903973524, 2551317.2612422374 6672889.818544494, 2551321.592248983 6672912.583769771, 2551325.197296503 6672931.528118047, 2551241.192264708 6672922.67608625, 2551065.2048991695 6672911.10342999, 2551041.9824534757 6672913.1939098155, 2551011.1951826657 6672922.7561046155, - 2550961.2442381973 6672948.942115062, 2550937.0813453244 6672957.334041252, 2550914.815845883 6672972.847602062, 2550869.4433942605 6673004.914962448, 2550737.005332743 6673085.04335423, 2550585.098364711 6673131.2839677865, 2550450.465926442 6673161.500903447, 2550327.5230816184 6673173.463649243, 2550187.660437108 6673162.511135324, 2550058.967665233 6673135.564950396, - 2549996.1556931143 6673120.591513559, 2549774.5483898534 6673069.78985311, 2549472.961828687 6672995.92289851, 2549214.371852586 6672931.748168554, 2549163.067984106 6672916.744724831, 2549161.253086041 6672916.204600857, 2549140.975724934 6672910.24323255, 2548982.9063530182 6672863.72255471, 2548979.8127767714 6672862.812345791, 2548865.771182002 6672820.342597757, - 2548836.0316023477 6672809.280058584, 2548832.525549268 6672807.819723395, 2548831.1808747924 6672807.259594829, 2548738.0518554533 6672768.48069395, 2548584.362987503 6672703.2157137515, 2548574.620284709 6672699.644894145, 2548403.161914796 6672636.710448871, 2548393.798690689 6672633.859794564, 2548383.8002522583 6672630.819096636, 2548259.2982450062 6672612.834968759, - 2548147.4097793056 6672620.4867250575, 2548121.2587480973 6672625.987987757, 2548090.2074921145 6672629.168717826, 2547920.7125119264 6672681.830805297, 2547882.871887273 6672694.0436084885, 2547881.403469748 6672694.513716391, 2547833.382916858 6672710.027277202, 2547685.3779796655 6672758.648437164, 2547673.3171570706 6672763.109461098, 2547663.2857204936 6672766.830315141, - 2547607.287865655 6672785.594622091, 2547597.809148034 6672788.495287878, 2547570.4371854006 6672796.867209476, 2547532.654307504 6672810.190267503, 2547314.5613068603 6672884.447311641, 2547067.850663547 6672968.146523029, 2547062.1089860327 6672970.096970713, 2547022.6514521944 6672983.550058586, 2546848.379990281 6673049.56521097, 2546831.484939204 6673057.83710961, +LINESTRING (2551018.1247934587 6672888.988353942, 2551072.6047335523 6672871.274288051, 2551102.270067377 6672869.903973524, 2551317.2612422374 6672889.818544494, 2551321.592248983 6672912.583769771, 2551325.197296503 6672931.528118047, 2551241.192264708 6672922.67608625, 2551065.2048991695 6672911.10342999, 2551041.9824534757 6672913.1939098155, 2551011.1951826657 6672922.7561046155, + 2550961.2442381973 6672948.942115062, 2550937.0813453244 6672957.334041252, 2550914.815845883 6672972.847602062, 2550869.4433942605 6673004.914962448, 2550737.005332743 6673085.04335423, 2550585.098364711 6673131.2839677865, 2550450.465926442 6673161.500903447, 2550327.5230816184 6673173.463649243, 2550187.660437108 6673162.511135324, 2550058.967665233 6673135.564950396, + 2549996.1556931143 6673120.591513559, 2549774.5483898534 6673069.78985311, 2549472.961828687 6672995.92289851, 2549214.371852586 6672931.748168554, 2549163.067984106 6672916.744724831, 2549161.253086041 6672916.204600857, 2549140.975724934 6672910.24323255, 2548982.9063530182 6672863.72255471, 2548979.8127767714 6672862.812345791, 2548865.771182002 6672820.342597757, + 2548836.0316023477 6672809.280058584, 2548832.525549268 6672807.819723395, 2548831.1808747924 6672807.259594829, 2548738.0518554533 6672768.48069395, 2548584.362987503 6672703.2157137515, 2548574.620284709 6672699.644894145, 2548403.161914796 6672636.710448871, 2548393.798690689 6672633.859794564, 2548383.8002522583 6672630.819096636, 2548259.2982450062 6672612.834968759, + 2548147.4097793056 6672620.4867250575, 2548121.2587480973 6672625.987987757, 2548090.2074921145 6672629.168717826, 2547920.7125119264 6672681.830805297, 2547882.871887273 6672694.0436084885, 2547881.403469748 6672694.513716391, 2547833.382916858 6672710.027277202, 2547685.3779796655 6672758.648437164, 2547673.3171570706 6672763.109461098, 2547663.2857204936 6672766.830315141, + 2547607.287865655 6672785.594622091, 2547597.809148034 6672788.495287878, 2547570.4371854006 6672796.867209476, 2547532.654307504 6672810.190267503, 2547314.5613068603 6672884.447311641, 2547067.850663547 6672968.146523029, 2547062.1089860327 6672970.096970713, 2547022.6514521944 6672983.550058586, 2546848.379990281 6673049.56521097, 2546831.484939204 6673057.83710961, 2546816.7595162685 6673065.048764894) -LINESTRING (2550184.0718886615 6676346.001838442, 2550178.858181493 6676383.270392652, 2550180.2771017984 6676468.249897904, 2550177.3732648944 6676527.243438627, 2550175.8718492226 6676545.997743282, 2550174.3951821607 6676564.371960695, 2550164.2812502175 6676695.402035885, 2550143.2531812745 6676741.2425576085, 2550075.136757084 6676897.898514678, 2550071.4079665146 6676906.480484488, - 2550063.5791562255 6676933.906779615, 2550055.882338523 6676982.537941873, 2550043.483284925 6677192.91622977, 2550037.131141698 6677349.362138627, 2550035.6709737093 6677366.696117276, 2550031.117229474 6677442.883604506, 2550033.0971182715 6677584.066009948, 2550031.5049576964 6677619.0840476, 2550029.3765772386 6677630.906761254, 2550023.1976742814 6677665.124615241, +LINESTRING (2550184.0718886615 6676346.001838442, 2550178.858181493 6676383.270392652, 2550180.2771017984 6676468.249897904, 2550177.3732648944 6676527.243438627, 2550175.8718492226 6676545.997743282, 2550174.3951821607 6676564.371960695, 2550164.2812502175 6676695.402035885, 2550143.2531812745 6676741.2425576085, 2550075.136757084 6676897.898514678, 2550071.4079665146 6676906.480484488, + 2550063.5791562255 6676933.906779615, 2550055.882338523 6676982.537941873, 2550043.483284925 6677192.91622977, 2550037.131141698 6677349.362138627, 2550035.6709737093 6677366.696117276, 2550031.117229474 6677442.883604506, 2550033.0971182715 6677584.066009948, 2550031.5049576964 6677619.0840476, 2550029.3765772386 6677630.906761254, 2550023.1976742814 6677665.124615241, 2550019.0399078056 6677686.849601753, 2550021.143539653 6677692.1808254225, 2550022.8016965217 6677696.371787369, 2550035.6874727826 6677729.009278617, 2550035.695722319 6677810.307939009) -LINESTRING (2553675.4737914735 6675736.161862543, 2553667.5707353544 6675743.563561447, 2553636.0575053184 6675773.070334104, 2553569.1702620904 6675865.6115749935, 2553545.0156187536 6675913.912661488, 2553506.539779778 6675989.219946686, 2553485.651952958 6676036.060697992, 2553474.5315775424 6676055.495158763, 2553471.5039975885 6676060.786373249, 2553457.2570477794 6676073.959396839, - 2553438.2088676346 6676092.903745115, 2553403.569063205 6676127.341649609, 2553366.2564088977 6676164.4401647905, 2553330.758652656 6676200.098349375, 2553295.4341366836 6676235.586494929, 2553280.9561998476 6676250.11983075, 2553266.857741698 6676263.442888777, 2553263.0299566886 6676267.053717567, 2553258.8721902124 6676270.974617526, 2553213.62348164 6676312.414129091, - 2553169.5132091264 6676352.803399596, 2553108.3923920225 6676400.944449359, 2553067.763423979 6676432.941793674, 2553014.4384190175 6676475.401539412, 2552967.5068049664 6676512.910148722, 2552964.231738913 6676515.460734155, 2552800.0082126497 6676643.68016422, 2552747.194678961 6676689.470674465, 2552732.5187532455 6676700.013094256, 2552601.0293884436 6676876.613629182, - 2552588.5065917955 6676903.429784264, 2552580.1250625504 6676934.786981648, 2552578.9866264914 6676950.380560825, 2552592.647859198 6677083.961221446, 2552604.74167994 6677178.863004148, 2552602.341064772 6677277.905737318, 2552604.881922063 6677633.767417857, 2552605.1294081626 6677756.13550487, 2552605.154156773 6677770.558815436, 2552599.9651982146 6677798.575246017, +LINESTRING (2553675.4737914735 6675736.161862543, 2553667.5707353544 6675743.563561447, 2553636.0575053184 6675773.070334104, 2553569.1702620904 6675865.6115749935, 2553545.0156187536 6675913.912661488, 2553506.539779778 6675989.219946686, 2553485.651952958 6676036.060697992, 2553474.5315775424 6676055.495158763, 2553471.5039975885 6676060.786373249, 2553457.2570477794 6676073.959396839, + 2553438.2088676346 6676092.903745115, 2553403.569063205 6676127.341649609, 2553366.2564088977 6676164.4401647905, 2553330.758652656 6676200.098349375, 2553295.4341366836 6676235.586494929, 2553280.9561998476 6676250.11983075, 2553266.857741698 6676263.442888777, 2553263.0299566886 6676267.053717567, 2553258.8721902124 6676270.974617526, 2553213.62348164 6676312.414129091, + 2553169.5132091264 6676352.803399596, 2553108.3923920225 6676400.944449359, 2553067.763423979 6676432.941793674, 2553014.4384190175 6676475.401539412, 2552967.5068049664 6676512.910148722, 2552964.231738913 6676515.460734155, 2552800.0082126497 6676643.68016422, 2552747.194678961 6676689.470674465, 2552732.5187532455 6676700.013094256, 2552601.0293884436 6676876.613629182, + 2552588.5065917955 6676903.429784264, 2552580.1250625504 6676934.786981648, 2552578.9866264914 6676950.380560825, 2552592.647859198 6677083.961221446, 2552604.74167994 6677178.863004148, 2552602.341064772 6677277.905737318, 2552604.881922063 6677633.767417857, 2552605.1294081626 6677756.13550487, 2552605.154156773 6677770.558815436, 2552599.9651982146 6677798.575246017, 2552592.4416207816 6677831.402780885, 2552588.836573262 6677847.116387612, 2552561.2501226757 6677966.763850162) -LINESTRING (2553644.7360178833 6677147.805875639, 2553666.4900460523 6677180.123293421, 2553675.4572924 6677195.976932289, 2553711.1447879854 6677259.091418888, 2553727.5943640824 6677300.7809878485, 2553750.1980945272 6677358.084140578, 2553789.837118172 6677473.050528687, 2553823.915954109 6677589.587277238, 2553855.2229457283 6677741.772208078, 2553875.120828149 6677877.7434174, +LINESTRING (2553644.7360178833 6677147.805875639, 2553666.4900460523 6677180.123293421, 2553675.4572924 6677195.976932289, 2553711.1447879854 6677259.091418888, 2553727.5943640824 6677300.7809878485, 2553750.1980945272 6677358.084140578, 2553789.837118172 6677473.050528687, 2553823.915954109 6677589.587277238, 2553855.2229457283 6677741.772208078, 2553875.120828149 6677877.7434174, 2553886.628931788 6677968.024139435, 2553888.5098261456 6678057.214611226) -LINESTRING (2554173.8860477777 6675504.448677671, 2554289.198071192 6675483.313826611, 2554368.5503643113 6675468.740481608, 2554388.472995342 6675467.460187743, 2554414.9292594064 6675465.779802047, 2554417.577360674 6675465.189666593, 2554451.491205877 6675457.627930956, 2554586.420627466 6675429.461465939, 2554623.0238216203 6675421.849718823, 2554651.063996723 6675416.008378066, +LINESTRING (2554173.8860477777 6675504.448677671, 2554289.198071192 6675483.313826611, 2554368.5503643113 6675468.740481608, 2554388.472995342 6675467.460187743, 2554414.9292594064 6675465.779802047, 2554417.577360674 6675465.189666593, 2554451.491205877 6675457.627930956, 2554586.420627466 6675429.461465939, 2554623.0238216203 6675421.849718823, 2554651.063996723 6675416.008378066, 2554673.997708634 6675411.237282962, 2554938.444855763 6675356.194649086, 2555013.4413935267 6675337.160280149, 2555039.9719034205 6675335.669938073) -LINESTRING (2553224.356128833 6671841.2578695165, 2553245.0954639926 6671840.097603202, 2553284.3385098777 6671818.292598323, 2553364.416762223 6671759.249046122, 2553385.3128385795 6671743.845510565, 2553534.835690517 6671645.212871524) \ No newline at end of file +LINESTRING (2553224.356128833 6671841.2578695165, 2553245.0954639926 6671840.097603202, 2553284.3385098777 6671818.292598323, 2553364.416762223 6671759.249046122, 2553385.3128385795 6671743.845510565, 2553534.835690517 6671645.212871524) diff --git a/data/Manhattan/bus.wkt b/data/Manhattan/bus.wkt index 08a4b117d..d490d506f 100644 --- a/data/Manhattan/bus.wkt +++ b/data/Manhattan/bus.wkt @@ -1,2 +1,2 @@ -LINESTRING (2549691.4669673573 6673187.82779412, 2550453.412051166 6673207.361937253, 2551222.2931330632 6673212.614600562, 2551968.1713229036 6673212.614600562, 2552703.235282084 6673187.82779412, 2552708.4879453927 6673891.68467749, 2552735.650626272 6674643.226953467, 2552724.8363956125 6675327.549693705, 2552730.089058921 6676020.901250457, 2551995.025099741 6676045.688056899, - 2551249.1469099005 6676045.688056899, 2550480.265828003 6676040.4353935905, 2549718.3207441946 6676020.901250457, 2549713.068080886 6675327.549693705, 2549723.8823115453 6674643.226953467, 2549696.719630666 6673891.68467749, 2549691.4669673573 6673187.82779412) \ No newline at end of file +LINESTRING (2549691.4669673573 6673187.82779412, 2550453.412051166 6673207.361937253, 2551222.2931330632 6673212.614600562, 2551968.1713229036 6673212.614600562, 2552703.235282084 6673187.82779412, 2552708.4879453927 6673891.68467749, 2552735.650626272 6674643.226953467, 2552724.8363956125 6675327.549693705, 2552730.089058921 6676020.901250457, 2551995.025099741 6676045.688056899, + 2551249.1469099005 6676045.688056899, 2550480.265828003 6676040.4353935905, 2549718.3207441946 6676020.901250457, 2549713.068080886 6675327.549693705, 2549723.8823115453 6674643.226953467, 2549696.719630666 6673891.68467749, 2549691.4669673573 6673187.82779412) diff --git a/data/Manhattan/roads.wkt b/data/Manhattan/roads.wkt index 0cee4380e..dec41cf3c 100644 --- a/data/Manhattan/roads.wkt +++ b/data/Manhattan/roads.wkt @@ -2556,4 +2556,4 @@ LINESTRING (2553824.5457668966 6672320.971424899, 2554011.040566236 6672320.5578 LINESTRING (2553650.572917482 6673717.766253239, 2553835.051093514 6673718.179865022) -LINESTRING (2548575.1428826493 6673019.575644961, 2548761.6376819885 6673019.162033177, 2548761.637681989 6673187.827794121, 2548577.7341701165 6673187.827794121, 2548575.1428826493 6673019.575644961) \ No newline at end of file +LINESTRING (2548575.1428826493 6673019.575644961, 2548761.6376819885 6673019.162033177, 2548761.637681989 6673187.827794121, 2548577.7341701165 6673187.827794121, 2548575.1428826493 6673019.575644961) diff --git a/data/ParkPOIs.wkt b/data/ParkPOIs.wkt index 32d6a09c0..ba940acd5 100644 --- a/data/ParkPOIs.wkt +++ b/data/ParkPOIs.wkt @@ -18,4 +18,4 @@ POINT (2552785.543273026 6673249.298489128) POINT (2552729.0506920097 6673245.719605062) -POINT (2552841.676618883 6673253.251878758) \ No newline at end of file +POINT (2552841.676618883 6673253.251878758) diff --git a/data/WestPOIs.wkt b/data/WestPOIs.wkt index 692cdf74e..1c5977d06 100644 --- a/data/WestPOIs.wkt +++ b/data/WestPOIs.wkt @@ -2,4 +2,4 @@ POINT (2550854.3137440286 6672591.750129179) POINT (2551121.9534618445 6672693.903576347) -POINT (2550700.913609861 6672866.723243455) \ No newline at end of file +POINT (2550700.913609861 6672866.723243455) diff --git a/data/cluster/ferryroute.wkt b/data/cluster/ferryroute.wkt index cae1f0c3b..f1d0375ac 100644 --- a/data/cluster/ferryroute.wkt +++ b/data/cluster/ferryroute.wkt @@ -1 +1 @@ -LINESTRING (100 -100, 600 -100, 350 -533, 100 -100) \ No newline at end of file +LINESTRING (100 -100, 600 -100, 350 -533, 100 -100) diff --git a/data/cluster/origin.wkt b/data/cluster/origin.wkt index a6612600b..d57e885f2 100644 --- a/data/cluster/origin.wkt +++ b/data/cluster/origin.wkt @@ -1 +1 @@ -LINESTRING (0 0, 100 -100) \ No newline at end of file +LINESTRING (0 0, 100 -100) diff --git a/data/demo_bus.wkt b/data/demo_bus.wkt index c306066a4..81aa07881 100644 --- a/data/demo_bus.wkt +++ b/data/demo_bus.wkt @@ -1,2 +1,2 @@ -LINESTRING (2550592.003226894 6672735.4731177585, 2551115.9395496203 6672778.863077007, 2551733.574109715 6672719.2894031275, 2552056.98894488 6672339.2921827845, 2552443.66947668 6672192.648523826, 2552707.5061580963 6671918.555611582, 2553198.6258239946 6672295.572147773, 2553076.243947664 6672827.414220898, 2552788.4341127174 6673214.002954185, 2553299.34441706 6673391.583714101, - 2553901.791580166 6673127.503099969, 2553449.865462933 6674015.21685593, 2552643.258766599 6673756.567488425, 2552068.1670670523 6673793.766026565, 2551642.8869532268 6674154.408804504, 2551301.966601272 6673840.286704404, 2551573.186617998 6673194.328438315, 2551303.7237525806 6672909.38303511, 2550592.003226894 6672735.4731177585) \ No newline at end of file +LINESTRING (2550592.003226894 6672735.4731177585, 2551115.9395496203 6672778.863077007, 2551733.574109715 6672719.2894031275, 2552056.98894488 6672339.2921827845, 2552443.66947668 6672192.648523826, 2552707.5061580963 6671918.555611582, 2553198.6258239946 6672295.572147773, 2553076.243947664 6672827.414220898, 2552788.4341127174 6673214.002954185, 2553299.34441706 6673391.583714101, + 2553901.791580166 6673127.503099969, 2553449.865462933 6674015.21685593, 2552643.258766599 6673756.567488425, 2552068.1670670523 6673793.766026565, 2551642.8869532268 6674154.408804504, 2551301.966601272 6673840.286704404, 2551573.186617998 6673194.328438315, 2551303.7237525806 6672909.38303511, 2550592.003226894 6672735.4731177585) diff --git a/data/main_roads.wkt b/data/main_roads.wkt index c06fc8a9f..5cbc05e3c 100644 --- a/data/main_roads.wkt +++ b/data/main_roads.wkt @@ -1,21 +1,21 @@ -MULTILINESTRING ((2551018.1247934587 6672888.988353942, 2551072.6047335523 6672871.274288051, 2551102.270067377 6672869.903973524, 2551317.2612422374 6672889.818544494), - (2551317.2612422374 6672889.818544494, 2551321.592248983 6672912.583769771, 2551325.197296503 6672931.528118047, 2551241.192264708 6672922.67608625, 2551065.2048991695 6672911.10342999, 2551041.9824534757 6672913.1939098155, 2551011.1951826657 6672922.7561046155, 2550961.2442381973 6672948.942115062, 2550937.0813453244 6672957.334041252, 2550914.815845883 6672972.847602062, - 2550869.4433942605 6673004.914962448, 2550737.005332743 6673085.04335423, 2550585.098364711 6673131.2839677865), - (2550585.098364711 6673131.2839677865, 2550450.465926442 6673161.500903447, 2550327.5230816184 6673173.463649243, 2550187.660437108 6673162.511135324, 2550186.3236131626 6673162.231226012), - (2552554.469003542 6673143.706819191, 2552508.7708714856 6673110.496865532, 2552459.211603745 6673074.480929848, 2552330.7745675067 6672982.3197762, 2552261.900555275 6672932.613958296, 2552203.5997103774 6672890.538709792, 2552065.320976905 6672790.54575852, 2551986.7936374517 6672734.5429042475, 2551898.243110958 6672671.248376324, 2551824.970726356 6672617.436024834, - 2551800.230365917 6672605.523290517), - (2551800.230365917 6672605.523290517, 2551795.8003647313 6672629.388768334, 2551790.0999349 6672641.201479693, 2551733.574109715 6672719.2894031275, 2551619.8624964124 6672639.221025121, 2551531.089232429 6672581.677817292, 2551522.3364740345 6672575.816471944, 2551503.8905100655 6672563.463636612, 2551487.9111575577 6672562.0333083095), - (2551006.2619597437 6672888.91833787, 2550832.7989524226 6672878.625975476, 2550815.9781471756 6672914.404187609, 2550792.821697775 6672954.823465002, 2550728.731047474 6673032.95139762, 2550585.098364711 6673131.2839677865), - (2551800.230365917 6672605.523290517, 2551785.174961515 6672603.022716563, 2551761.795774624 6672609.224139969, 2551737.7731238743 6672604.973164247, 2551675.596366078 6672560.723007558, 2551609.583573736 6672512.792006007, 2551592.7710180255 6672511.671748877, 2551562.9076953214 6672521.093911535, 2551507.050082606 6672544.609308998, 2551487.9111575577 6672562.0333083095), +MULTILINESTRING ((2551018.1247934587 6672888.988353942, 2551072.6047335523 6672871.274288051, 2551102.270067377 6672869.903973524, 2551317.2612422374 6672889.818544494), + (2551317.2612422374 6672889.818544494, 2551321.592248983 6672912.583769771, 2551325.197296503 6672931.528118047, 2551241.192264708 6672922.67608625, 2551065.2048991695 6672911.10342999, 2551041.9824534757 6672913.1939098155, 2551011.1951826657 6672922.7561046155, 2550961.2442381973 6672948.942115062, 2550937.0813453244 6672957.334041252, 2550914.815845883 6672972.847602062, + 2550869.4433942605 6673004.914962448, 2550737.005332743 6673085.04335423, 2550585.098364711 6673131.2839677865), + (2550585.098364711 6673131.2839677865, 2550450.465926442 6673161.500903447, 2550327.5230816184 6673173.463649243, 2550187.660437108 6673162.511135324, 2550186.3236131626 6673162.231226012), + (2552554.469003542 6673143.706819191, 2552508.7708714856 6673110.496865532, 2552459.211603745 6673074.480929848, 2552330.7745675067 6672982.3197762, 2552261.900555275 6672932.613958296, 2552203.5997103774 6672890.538709792, 2552065.320976905 6672790.54575852, 2551986.7936374517 6672734.5429042475, 2551898.243110958 6672671.248376324, 2551824.970726356 6672617.436024834, + 2551800.230365917 6672605.523290517), + (2551800.230365917 6672605.523290517, 2551795.8003647313 6672629.388768334, 2551790.0999349 6672641.201479693, 2551733.574109715 6672719.2894031275, 2551619.8624964124 6672639.221025121, 2551531.089232429 6672581.677817292, 2551522.3364740345 6672575.816471944, 2551503.8905100655 6672563.463636612, 2551487.9111575577 6672562.0333083095), + (2551006.2619597437 6672888.91833787, 2550832.7989524226 6672878.625975476, 2550815.9781471756 6672914.404187609, 2550792.821697775 6672954.823465002, 2550728.731047474 6673032.95139762, 2550585.098364711 6673131.2839677865), + (2551800.230365917 6672605.523290517, 2551785.174961515 6672603.022716563, 2551761.795774624 6672609.224139969, 2551737.7731238743 6672604.973164247, 2551675.596366078 6672560.723007558, 2551609.583573736 6672512.792006007, 2551592.7710180255 6672511.671748877, 2551562.9076953214 6672521.093911535, 2551507.050082606 6672544.609308998, 2551487.9111575577 6672562.0333083095), (2551487.9111575577 6672562.0333083095, 2551420.1329643703 6672640.221254703, 2551414.6140243458 6672657.84529993, 2551395.013125245 6672698.214565843, 2551382.737814697 6672714.818376898, 2551364.7703238544 6672731.342169586, 2551332.7043748624 6672762.019210854, 2551326.104745535 6672791.0058641285, 2551317.2612422374 6672889.818544494)) -LINESTRING (2552559.517719977 6673146.45745054, 2552473.318311431 6673253.912114491, 2552440.104393391 6673297.548247428, 2552408.7574375407 6673338.7315830095, 2552398.0412894213 6673352.814815518, 2552387.0611561285 6673365.997841404, 2552275.9398973365 6673509.820852942, 2552256.454491749 6673534.296470803, 2552195.9111422114 6673612.1843483215, 2552172.432960881 6673639.590638857, - 2552153.657015446 6673654.484057328, 2552149.2847610167 6673657.954853976, 2552146.0756912567 6673660.495437113, 2552144.1535492153 6673662.015786077, 2552140.721741965 6673665.156506963, 2552137.4466759115 6673668.147193412, 2552124.4206575276 6673683.880804731, 2552092.0164775327 6673747.715456628, 2552068.1670670523 6673793.766026565, 2552022.431635817 6673885.937182508, +LINESTRING (2552559.517719977 6673146.45745054, 2552473.318311431 6673253.912114491, 2552440.104393391 6673297.548247428, 2552408.7574375407 6673338.7315830095, 2552398.0412894213 6673352.814815518, 2552387.0611561285 6673365.997841404, 2552275.9398973365 6673509.820852942, 2552256.454491749 6673534.296470803, 2552195.9111422114 6673612.1843483215, 2552172.432960881 6673639.590638857, + 2552153.657015446 6673654.484057328, 2552149.2847610167 6673657.954853976, 2552146.0756912567 6673660.495437113, 2552144.1535492153 6673662.015786077, 2552140.721741965 6673665.156506963, 2552137.4466759115 6673668.147193412, 2552124.4206575276 6673683.880804731, 2552092.0164775327 6673747.715456628, 2552068.1670670523 6673793.766026565, 2552022.431635817 6673885.937182508, 2551970.2203183044 6673991.151332197, 2551943.3598269443 6674056.316289438, 2551910.081196063 6674119.950895418, 2551906.723634643 6674125.11208006, 2551861.5739205102 6674198.388899207, 2551849.810081235 6674219.603768633, 2551800.86558024 6674295.731242088, 2551770.499035799 6674351.273990754, 2551761.5729668215 6674388.38925647) -LINESTRING (2552565.003661855 6673149.448136989, 2552576.849996497 6673154.089202248, 2552643.456755479 6673204.110683623, 2552681.874847698 6673207.531468792, 2552788.4341127174 6673214.002954185, 2552892.741254229 6673220.99455896, 2552983.1231778613 6673226.425805588, 2552993.2701079515 6673230.756799676, 2553050.2414081157 6673236.108027938, 2553055.265375941 6673247.010530378, - 2553055.669603237 6673293.861283979, 2553119.9004956614 6673301.242978292, 2553205.6544292276 6673309.334835607, 2553290.806146618 6673314.916116672, 2553304.1373978583 6673315.44623835, 2553311.495984558 6673318.586959236, 2553315.5877547404 6673324.248258668, 2553324.134274719 6673336.040965435, 2553344.139401116 6673364.037391424, 2553379.109187012 6673412.298468736, - 2553382.615240092 6673431.512878998, 2553383.2587039513 6673452.957801227, 2553384.355892327 6673489.416169477, 2553390.7657823106 6673499.708531871, 2553398.388354183 6673503.7994708605, 2553399.287553679 6673503.929500706, 2553433.0446576863 6673508.920646318, 2553438.126372268 6673509.670818504, 2553443.909297466 6673513.061596786, 2553451.424625362 6673526.524686954, - 2553479.8277800772 6673656.594541744, 2553493.3322715876 6673718.438736775, 2553545.51884049 6673950.411981339, 2553561.6796828043 6674022.26847448, 2553559.7905389094 6674043.833424259, 2553548.8516533 6674160.680243981, 2553547.647220948 6674163.500891401, 2553538.020011667 6674185.976050099, 2553503.4132053843 6674218.46350691, 2553481.741672582 6674232.366698094, - 2553470.2088203332 6674233.837035579, 2553446.1614209735 6674233.516962113, 2553433.2838942492 6674233.7470149165, 2553381.4190572766 6674234.637219245, 2553366.974118587 6674236.167570504, 2553355.1937802387 6674240.948667904, 2553331.1958780987 6674260.173080462, 2553328.6632703445 6674268.35495844, 2553317.6418893686 6674303.933124657, 2553310.6380327456 6674361.746394473, - 2553308.7473131865 6674388.38925647) \ No newline at end of file +LINESTRING (2552565.003661855 6673149.448136989, 2552576.849996497 6673154.089202248, 2552643.456755479 6673204.110683623, 2552681.874847698 6673207.531468792, 2552788.4341127174 6673214.002954185, 2552892.741254229 6673220.99455896, 2552983.1231778613 6673226.425805588, 2552993.2701079515 6673230.756799676, 2553050.2414081157 6673236.108027938, 2553055.265375941 6673247.010530378, + 2553055.669603237 6673293.861283979, 2553119.9004956614 6673301.242978292, 2553205.6544292276 6673309.334835607, 2553290.806146618 6673314.916116672, 2553304.1373978583 6673315.44623835, 2553311.495984558 6673318.586959236, 2553315.5877547404 6673324.248258668, 2553324.134274719 6673336.040965435, 2553344.139401116 6673364.037391424, 2553379.109187012 6673412.298468736, + 2553382.615240092 6673431.512878998, 2553383.2587039513 6673452.957801227, 2553384.355892327 6673489.416169477, 2553390.7657823106 6673499.708531871, 2553398.388354183 6673503.7994708605, 2553399.287553679 6673503.929500706, 2553433.0446576863 6673508.920646318, 2553438.126372268 6673509.670818504, 2553443.909297466 6673513.061596786, 2553451.424625362 6673526.524686954, + 2553479.8277800772 6673656.594541744, 2553493.3322715876 6673718.438736775, 2553545.51884049 6673950.411981339, 2553561.6796828043 6674022.26847448, 2553559.7905389094 6674043.833424259, 2553548.8516533 6674160.680243981, 2553547.647220948 6674163.500891401, 2553538.020011667 6674185.976050099, 2553503.4132053843 6674218.46350691, 2553481.741672582 6674232.366698094, + 2553470.2088203332 6674233.837035579, 2553446.1614209735 6674233.516962113, 2553433.2838942492 6674233.7470149165, 2553381.4190572766 6674234.637219245, 2553366.974118587 6674236.167570504, 2553355.1937802387 6674240.948667904, 2553331.1958780987 6674260.173080462, 2553328.6632703445 6674268.35495844, 2553317.6418893686 6674303.933124657, 2553310.6380327456 6674361.746394473, + 2553308.7473131865 6674388.38925647) diff --git a/data/pedestrian_paths.wkt b/data/pedestrian_paths.wkt index 9295e86c0..997c85e8e 100644 --- a/data/pedestrian_paths.wkt +++ b/data/pedestrian_paths.wkt @@ -28,4 +28,4 @@ LINESTRING (2553171.039373408 6672675.199283171, 2553072.3655058085 6672628.6252 LINESTRING (2552924.1307412153 6672763.979660833, 2552946.75055431 6672726.8954462055, 2552980.076970014 6672720.913781848, 2553015.3458680497 6672745.815491632) -LINESTRING (2552990.331251769 6672620.934534737, 2552980.076970014 6672720.913781848) \ No newline at end of file +LINESTRING (2552990.331251769 6672620.934534737, 2552980.076970014 6672720.913781848) diff --git a/data/roads.wkt b/data/roads.wkt index f1da873fc..4aa7becb0 100644 --- a/data/roads.wkt +++ b/data/roads.wkt @@ -18,7 +18,7 @@ LINESTRING (2551086.298964406 6671839.64749989, 2551006.228961597 6671778.523470 LINESTRING (2551596.433812302 6671064.409560379, 2551481.427021744 6671124.963459249) -LINESTRING (2551481.427021744 6671124.963459249, 2551445.178557666 6671054.67732655, 2551435.180119236 6671046.105359036, 2551419.3410088513 6671039.603866755, 2551404.846572942 6671040.844151436, 2551386.400608973 6671047.835756212, 2551312.4600119023 6671088.845169057, 2551297.338611207 6671100.237783992, 2551288.8415884483 6671108.17960687, 2551285.1210474153 6671126.433796734, +LINESTRING (2551481.427021744 6671124.963459249, 2551445.178557666 6671054.67732655, 2551435.180119236 6671046.105359036, 2551419.3410088513 6671039.603866755, 2551404.846572942 6671040.844151436, 2551386.400608973 6671047.835756212, 2551312.4600119023 6671088.845169057, 2551297.338611207 6671100.237783992, 2551288.8415884483 6671108.17960687, 2551285.1210474153 6671126.433796734, 2551335.657708986 6671225.196465621, 2551491.2522199047 6671144.017832778) LINESTRING (2551491.2522199047 6671144.017832778, 2551481.427021744 6671124.963459249) @@ -27,7 +27,7 @@ LINESTRING (2551618.7735575736 6671352.915780894, 2551528.9278538246 6671397.786 LINESTRING (2551528.9278538246 6671397.786079925, 2551436.2773076114 6671444.056700369) -LINESTRING (2551906.43490086 6671776.923102828, 2551921.572800629 6671722.220547011, 2551916.697324463 6671708.97750735, 2551897.690392002 6671693.523960315, 2551873.7749852287 6671666.857839669, 2551855.8652411425 6671639.501560613, 2551795.7261189013 6671523.915030164, 2551805.782304088 6671476.494145701, 2551804.5366240526 6671466.011739685, 2551679.473648308 6671222.705893962, +LINESTRING (2551906.43490086 6671776.923102828, 2551921.572800629 6671722.220547011, 2551916.697324463 6671708.97750735, 2551897.690392002 6671693.523960315, 2551873.7749852287 6671666.857839669, 2551855.8652411425 6671639.501560613, 2551795.7261189013 6671523.915030164, 2551805.782304088 6671476.494145701, 2551804.5366240526 6671466.011739685, 2551679.473648308 6671222.705893962, 2551671.422100529 6671215.784305258, 2551660.813196386 6671215.63427082, 2551571.1077347603 6671261.264744333, 2551561.926000459 6671263.085162171, 2551553.84970407 6671260.544579034, 2551547.093333547 6671252.882820439, 2551491.2522199047 6671144.017832778) LINESTRING (2551626.5116229593 6671587.909718794, 2551528.9278538246 6671397.786079925) @@ -198,7 +198,7 @@ LINESTRING (2552909.710551136 6672140.6265832875, 2552883.7245106613 6672239.799 LINESTRING (2552883.7245106613 6672239.799346303, 2552708.001130296 6672220.484913082) -LINESTRING (2553258.6824508696 6671752.257441346, 2553307.899186575 6671743.005317716, 2553327.4588379925 6671743.275379703, 2553356.2414713944 6671753.047622715, 2553364.416762223 6671759.249046122, 2553372.229073439 6671765.190409836, 2553384.3393932534 6671781.114064775, 2553425.45508396 6671872.695085266, 2553439.4132999866 6671885.367994064, 2553475.3317825985 6671896.300503392, +LINESTRING (2553258.6824508696 6671752.257441346, 2553307.899186575 6671743.005317716, 2553327.4588379925 6671743.275379703, 2553356.2414713944 6671753.047622715, 2553364.416762223 6671759.249046122, 2553372.229073439 6671765.190409836, 2553384.3393932534 6671781.114064775, 2553425.45508396 6671872.695085266, 2553439.4132999866 6671885.367994064, 2553475.3317825985 6671896.300503392, 2553498.7274685623 6671899.161159995, 2553558.3551195306 6671918.175524341, 2553586.8572686864 6671931.4285662975) LINESTRING (2553477.5591574963 6672131.244429813, 2553501.581808246 6672095.446213087, 2553524.688760427 6672067.959904185, 2553578.236502878 6672029.551088251, 2553588.5484237014 6672013.887493004, 2553596.9794501667 6671997.5837508235, 2553598.4066200084 6671985.601000437, 2553597.391926999 6671967.896936842, 2553586.8572686864 6671931.4285662975) @@ -1719,7 +1719,7 @@ LINESTRING (2551590.560142201 6673751.856407096, 2551590.659136641 6673766.41974 LINESTRING (2551840.6200973974 6673766.099676338, 2551813.8668500134 6673803.158182336) -LINESTRING (2552118.0437656906 6673737.923209025, 2552177.8364073923 6673801.157723173, 2552199.0789642883 6673818.001589327, 2552221.748691026 6673826.953644082, 2552240.5658841445 6673806.108859601, 2552297.924912532 6673716.958396994, 2552318.0207838323 6673714.7078804355, 2552341.8371961657 6673705.855848638, 2552354.4919854 6673692.762843415, 2552359.6396962753 6673678.47956499, +LINESTRING (2552118.0437656906 6673737.923209025, 2552177.8364073923 6673801.157723173, 2552199.0789642883 6673818.001589327, 2552221.748691026 6673826.953644082, 2552240.5658841445 6673806.108859601, 2552297.924912532 6673716.958396994, 2552318.0207838323 6673714.7078804355, 2552341.8371961657 6673705.855848638, 2552354.4919854 6673692.762843415, 2552359.6396962753 6673678.47956499, 2552359.0127314893 6673658.444966471) LINESTRING (2552622.8329138323 6673749.445853804, 2552599.197991305 6673743.634519935) @@ -1748,7 +1748,7 @@ LINESTRING (2550933.6990352944 6673730.841583586, 2550817.034087868 6673801.0276 LINESTRING (2550817.034087868 6673801.027693327, 2550802.3251640056 6673777.652328005) -LINESTRING (2550933.6990352944 6673730.841583586, 2550952.3512376794 6673762.378822294, 2550956.591499522 6673790.235216142, 2550954.025893621 6673808.149327948, 2550946.8735453384 6673823.68289335, 2550935.695423166 6673836.845914644, 2550919.9223090746 6673848.198520395, 2550889.720755367 6673857.050552192, 2550856.8546013194 6673849.638850993, 2550839.654317386 6673838.396270496, +LINESTRING (2550933.6990352944 6673730.841583586, 2550952.3512376794 6673762.378822294, 2550956.591499522 6673790.235216142, 2550954.025893621 6673808.149327948, 2550946.8735453384 6673823.68289335, 2550935.695423166 6673836.845914644, 2550919.9223090746 6673848.198520395, 2550889.720755367 6673857.050552192, 2550856.8546013194 6673849.638850993, 2550839.654317386 6673838.396270496, 2550818.6674961266 6673809.159559825, 2550817.034087868 6673801.027693327) LINESTRING (2551219.034009243 6673822.6826637685, 2551179.254743475 6673814.2407261, 2551136.8603745867 6673805.238659865) @@ -1801,7 +1801,7 @@ LINESTRING (2551458.163328367 6673872.90419106, 2551403.881377153 6673861.881661 LINESTRING (2551731.78396026 6673845.057799509, 2551679.712884871 6673895.7394324085) -LINESTRING (2551010.510471123 6674129.593108585, 2551015.4271949716 6674107.267984324, 2551014.2392616924 6674078.951484869, 2551005.090525538 6674055.06600246, 2550970.731205355 6674013.506463345, 2550957.655689751 6673913.943610793, 2550959.4458392058 6673875.394762719, 2550972.37286315 6673819.982043899, 2550981.414355328 6673794.056093143, 2551025.4503820115 6673705.495765989, +LINESTRING (2551010.510471123 6674129.593108585, 2551015.4271949716 6674107.267984324, 2551014.2392616924 6674078.951484869, 2551005.090525538 6674055.06600246, 2550970.731205355 6674013.506463345, 2550957.655689751 6673913.943610793, 2550959.4458392058 6673875.394762719, 2550972.37286315 6673819.982043899, 2550981.414355328 6673794.056093143, 2551025.4503820115 6673705.495765989, 2551039.1363633284 6673648.872769374) LINESTRING (2551189.6904073483 6673933.678140438, 2551121.846217868 6673914.833815121) @@ -1814,7 +1814,7 @@ LINESTRING (2551201.2315091337 6673936.978898058, 2551195.696070036 6673935.3985 LINESTRING (2551197.78320281 6673927.316680299, 2551221.475872094 6673934.808399865, 2551230.715353152 6673946.261028575) -LINESTRING (2550674.9523179964 6674116.500103362, 2550664.4836559766 6674113.329375588, 2550650.0139686773 6674100.476425465, 2550640.1475228337 6674080.841918779, 2550633.943871266 6674042.0630179, 2550645.8562022015 6673991.161334492, 2550645.410727222 6673981.349082297, 2550637.8129039593 6673962.314713359, 2550616.265114207 6673944.200555637, 2550609.1292649973 6673933.918195537, +LINESTRING (2550674.9523179964 6674116.500103362, 2550664.4836559766 6674113.329375588, 2550650.0139686773 6674100.476425465, 2550640.1475228337 6674080.841918779, 2550633.943871266 6674042.0630179, 2550645.8562022015 6673991.161334492, 2550645.410727222 6673981.349082297, 2550637.8129039593 6673962.314713359, 2550616.265114207 6673944.200555637, 2550609.1292649973 6673933.918195537, 2550602.87611621 6673919.264832167, 2550599.832037183 6673900.880612458, 2550603.0493564797 6673873.6943724295, 2550611.1504014786 6673856.980536122) LINESTRING (2551121.846217868 6673914.833815121, 2551116.9047454093 6673924.63606502, 2551105.1574052074 6673931.647674387, 2551100.4386702385 6673938.219182739, 2551075.632313506 6674031.200524644, 2551082.7021664227 6674042.903210748, 2551160.1818147204 6674064.618194965) @@ -1897,7 +1897,7 @@ LINESTRING (2552017.9191392646 6673946.871168619, 2552033.906741309 6673956.7334 LINESTRING (2552103.912309394 6674035.331472816, 2552084.14641956 6674019.7879051175) -LINESTRING (2552540.7087763953 6673856.620453472, 2552537.656447832 6673859.791181246, 2552526.197841413 6673969.586382417, 2552522.6257920396 6673981.93921775, 2552497.6379455007 6674020.528075008, 2552484.6531748 6674074.850543585, 2552475.850919185 6674149.257622159, 2552457.3059607767 6674203.500072369, 2552433.3163081734 6674251.000975199, 2552457.9659237093 6674315.865863565, +LINESTRING (2552540.7087763953 6673856.620453472, 2552537.656447832 6673859.791181246, 2552526.197841413 6673969.586382417, 2552522.6257920396 6673981.93921775, 2552497.6379455007 6674020.528075008, 2552484.6531748 6674074.850543585, 2552475.850919185 6674149.257622159, 2552457.3059607767 6674203.500072369, 2552433.3163081734 6674251.000975199, 2552457.9659237093 6674315.865863565, 2552469.9772490845 6674314.32551001, 2552538.7948838905 6674256.922334322, 2552572.4117457746 6674236.2575911665, 2552769.740662649 6674190.066989088, 2552873.2723477148 6674175.9337451, 2552913.356846339 6674178.394309871) LINESTRING (2552103.912309394 6674035.331472816, 2552113.457023308 6674034.611307517, 2552123.8679385716 6674040.122572511, 2552211.725503986 6674130.563331279, 2552231.623386407 6674164.851201337, 2552240.7556234878 6674189.7869248055) @@ -2146,4 +2146,4 @@ LINESTRING (2552908.753604884 6674299.502107611, 2552904.4841809357 6674388.3892 LINESTRING (2552915.658467067 6674300.512339488, 2552992.4286552123 6674304.88334276, 2553005.4134259126 6674311.614887844, 2553009.026722969 6674320.076830104, 2553005.1839963407 6674388.38925647) -LINESTRING (2552733.706686524 6674363.156718183, 2552732.181598501 6674388.38925647) \ No newline at end of file +LINESTRING (2552733.706686524 6674363.156718183, 2552732.181598501 6674388.38925647) diff --git a/data/shops.wkt b/data/shops.wkt index 0db258f86..306639b4b 100644 --- a/data/shops.wkt +++ b/data/shops.wkt @@ -68,4 +68,4 @@ POINT (2552844.716030899 6673485.8301613815) POINT (2552847.2814310095 6673449.964078932) -POINT (2552800.516540576 6673446.05062009) \ No newline at end of file +POINT (2552800.516540576 6673446.05062009) diff --git a/data/throwboxes.wkt b/data/throwboxes.wkt index 781180028..bcba36407 100644 --- a/data/throwboxes.wkt +++ b/data/throwboxes.wkt @@ -8,4 +8,4 @@ LINESTRING (2552017.9191392646 6673946.871168619) LINESTRING (2551949.8274636846 6673239.518810811) -LINESTRING (2552473.318311431 6673253.912114491) \ No newline at end of file +LINESTRING (2552473.318311431 6673253.912114491) diff --git a/data/tram10.wkt b/data/tram10.wkt index abbf36bb5..19ad6c594 100644 --- a/data/tram10.wkt +++ b/data/tram10.wkt @@ -1 +1 @@ -LINESTRING (2552787.726166266 6672530.040305593, 2552686.56058452 6672754.707532612, 2552579.465099618 6673027.760206092, 2552440.104393391 6673297.548247428, 2552172.432960881 6673639.590638857, 2551943.3598269443 6674056.316289438, 2551761.5729668215 6674388.38925647) \ No newline at end of file +LINESTRING (2552787.726166266 6672530.040305593, 2552686.56058452 6672754.707532612, 2552579.465099618 6673027.760206092, 2552440.104393391 6673297.548247428, 2552172.432960881 6673639.590638857, 2551943.3598269443 6674056.316289438, 2551761.5729668215 6674388.38925647) diff --git a/data/tram3.wkt b/data/tram3.wkt index a43536365..d8a2186f1 100644 --- a/data/tram3.wkt +++ b/data/tram3.wkt @@ -1,2 +1,2 @@ -LINESTRING (2552480.8583879373 6673392.573941387, 2552720.809051393 6673409.434952837, 2552930.1703346907 6673422.44040407, 2553055.669603237 6673293.861283979, 2553058.119715625 6673058.3372244015, 2553281.9791423935 6672606.85359586, 2553180.9635660085 6672364.467961353, 2552883.7245106613 6672239.799346303, 2552708.001130296 6672220.484913082, 2552440.7491407027 6672213.753367998, - 2552483.811722061 6672500.92928317, 2552341.7794494093 6672696.104081427, 2552261.900555275 6672932.613958296, 2552508.7708714856 6673110.496865532) \ No newline at end of file +LINESTRING (2552480.8583879373 6673392.573941387, 2552720.809051393 6673409.434952837, 2552930.1703346907 6673422.44040407, 2553055.669603237 6673293.861283979, 2553058.119715625 6673058.3372244015, 2553281.9791423935 6672606.85359586, 2553180.9635660085 6672364.467961353, 2552883.7245106613 6672239.799346303, 2552708.001130296 6672220.484913082, 2552440.7491407027 6672213.753367998, + 2552483.811722061 6672500.92928317, 2552341.7794494093 6672696.104081427, 2552261.900555275 6672932.613958296, 2552508.7708714856 6673110.496865532) diff --git a/data/tram4.wkt b/data/tram4.wkt index 57a9effea..68659f84f 100644 --- a/data/tram4.wkt +++ b/data/tram4.wkt @@ -1,2 +1,2 @@ -LINESTRING (2554383.251038637 6673258.043062663, 2554164.2258403506 6673085.173384075, 2553841.6277093147 6673119.391238062, 2553707.4902432454 6673207.421443538, 2553241.3996715695 6673442.8554824535, 2552930.1703346907 6673422.44040407, 2552720.809051393 6673409.434952837, 2552480.8583879373 6673392.573941387, 2552172.432960881 6673639.590638857, 2551943.3598269443 6674056.316289438, - 2551761.5729668215 6674388.38925647) \ No newline at end of file +LINESTRING (2554383.251038637 6673258.043062663, 2554164.2258403506 6673085.173384075, 2553841.6277093147 6673119.391238062, 2553707.4902432454 6673207.421443538, 2553241.3996715695 6673442.8554824535, 2552930.1703346907 6673422.44040407, 2552720.809051393 6673409.434952837, 2552480.8583879373 6673392.573941387, 2552172.432960881 6673639.590638857, 2551943.3598269443 6674056.316289438, + 2551761.5729668215 6674388.38925647) diff --git a/default_settings.txt b/default_settings.txt index 3af13ebe9..fc266f1ba 100644 --- a/default_settings.txt +++ b/default_settings.txt @@ -1 +1,183 @@ -# # Default settings for the simulation # ## Scenario settings Scenario.name = default_scenario Scenario.simulateConnections = true Scenario.updateInterval = 0.1 # 43200s == 12h Scenario.endTime = 10000000 Scenario.endTime = 43200 ## Interface-specific settings: # type : which interface class the interface belongs to # For different types, the sub-parameters are interface-specific # For SimpleBroadcastInterface, the parameters are: # transmitSpeed : transmit speed of the interface (bytes per second) # transmitRange : range of the interface (meters) # "Bluetooth" interface for all nodes btInterface.type = SimpleBroadcastInterface # Transmit speed of 2 Mbps = 250kBps btInterface.transmitSpeed = 250k btInterface.transmitRange = 10 # High speed, long range, interface for group 4 highspeedInterface.type = SimpleBroadcastInterface highspeedInterface.transmitSpeed = 10M highspeedInterface.transmitRange = 10 # Define 6 different node groups Scenario.nrofHostGroups = 6 ## Group-specific settings: # groupID : Group's identifier. Used as the prefix of host names # nrofHosts: number of hosts in the group # movementModel: movement model of the hosts (valid class name from movement package) # waitTime: minimum and maximum wait times (seconds) after reaching destination # speed: minimum and maximum speeds (m/s) when moving on a path # bufferSize: size of the message buffer (bytes) # router: router used to route messages (valid class name from routing package) # activeTimes: Time intervals when the nodes in the group are active (start1, end1, start2, end2, ...) # msgTtl : TTL (minutes) of the messages created by this host group, default=infinite ## Group and movement model specific settings # pois: Points Of Interest indexes and probabilities (poiIndex1, poiProb1, poiIndex2, poiProb2, ... ) # for ShortestPathMapBasedMovement # okMaps : which map nodes are OK for the group (map file indexes), default=all # for all MapBasedMovent models # routeFile: route's file path - for MapRouteMovement # routeType: route's type - for MapRouteMovement # Common settings for all groups Group.movementModel = ShortestPathMapBasedMovement Group.router = EpidemicRouter Group.bufferSize = 5M Group.waitTime = 0, 120 # All nodes have the bluetooth interface Group.nrofInterfaces = 1 Group.interface1 = btInterface # Walking speeds Group.speed = 0.5, 1.5 # Message TTL of 300 minutes (5 hours) Group.msgTtl = 300 Group.nrofHosts = 40 # group1 (pedestrians) specific settings Group1.groupID = p # group2 specific settings Group2.groupID = c # cars can drive only on roads Group2.okMaps = 1 # 10-50 km/h Group2.speed = 2.7, 13.9 # another group of pedestrians Group3.groupID = w # The Tram groups Group4.groupID = t Group4.bufferSize = 50M Group4.movementModel = MapRouteMovement Group4.routeFile = data/tram3.wkt Group4.routeType = 1 Group4.waitTime = 10, 30 Group4.speed = 7, 10 Group4.nrofHosts = 2 Group4.nrofInterfaces = 2 Group4.interface1 = btInterface Group4.interface2 = highspeedInterface Group5.groupID = t Group5.bufferSize = 50M Group5.movementModel = MapRouteMovement Group5.routeFile = data/tram4.wkt Group5.routeType = 2 Group5.waitTime = 10, 30 Group5.speed = 7, 10 Group5.nrofHosts = 2 Group6.groupID = t Group6.bufferSize = 50M Group6.movementModel = MapRouteMovement Group6.routeFile = data/tram10.wkt Group6.routeType = 2 Group6.waitTime = 10, 30 Group6.speed = 7, 10 Group6.nrofHosts = 2 ## Message creation parameters # How many event generators Events.nrof = 1 # Class of the first event generator Events1.class = MessageEventGenerator # (following settings are specific for the MessageEventGenerator class) # Creation interval in seconds (one new message every 25 to 35 seconds) Events1.interval = 25,35 # Message sizes (500kB - 1MB) Events1.size = 500k,1M # range of message source/destination addresses Events1.hosts = 0,125 # Message ID prefix Events1.prefix = M ## Movement model settings # seed for movement models' pseudo random number generator (default = 0) MovementModel.rngSeed = 1 # World's size for Movement Models without implicit size (width, height; meters) MovementModel.worldSize = 4500, 3400 # How long time to move hosts in the world before real simulation MovementModel.warmup = 1000 ## Map based movement -movement model specific settings MapBasedMovement.nrofMapFiles = 4 MapBasedMovement.mapFile1 = data/roads.wkt MapBasedMovement.mapFile2 = data/main_roads.wkt MapBasedMovement.mapFile3 = data/pedestrian_paths.wkt MapBasedMovement.mapFile4 = data/shops.wkt ## Reports - all report names have to be valid report classes # how many reports to load Report.nrofReports = 2 # length of the warm up period (simulated seconds) Report.warmup = 0 # default directory of reports (can be overridden per Report with output setting) Report.reportDir = reports/ # Report classes to load Report.report1 = ContactTimesReport Report.report2 = ConnectivityONEReport ## Default settings for some routers settings ProphetRouter.secondsInTimeUnit = 30 SprayAndWaitRouter.nrofCopies = 6 SprayAndWaitRouter.binaryMode = true ## Optimization settings -- these affect the speed of the simulation ## see World class for details. Optimization.cellSizeMult = 5 Optimization.randomizeUpdateOrder = true ## GUI settings # GUI underlay image settings GUI.UnderlayImage.fileName = data/helsinki_underlay.png # Image offset in pixels (x, y) GUI.UnderlayImage.offset = 64, 20 # Scaling factor for the image GUI.UnderlayImage.scale = 4.75 # Image rotation (radians) GUI.UnderlayImage.rotate = -0.015 # how many events to show in the log panel (default = 30) GUI.EventLogPanel.nrofEvents = 100 # Regular Expression log filter (see Pattern-class from the Java API for RE-matching details) #GUI.EventLogPanel.REfilter = .*p[1-9]<->p[1-9]$ \ No newline at end of file +# +# Default settings for the simulation +# + +## Scenario settings +Scenario.name = default_scenario +Scenario.simulateConnections = true +Scenario.updateInterval = 0.1 +# 43200s == 12h +Scenario.endTime = 10000000 +Scenario.endTime = 43200 + +## Interface-specific settings: +# type : which interface class the interface belongs to +# For different types, the sub-parameters are interface-specific +# For SimpleBroadcastInterface, the parameters are: +# transmitSpeed : transmit speed of the interface (bytes per second) +# transmitRange : range of the interface (meters) + +# "Bluetooth" interface for all nodes +btInterface.type = SimpleBroadcastInterface +# Transmit speed of 2 Mbps = 250kBps +btInterface.transmitSpeed = 250k +btInterface.transmitRange = 10 + +# High speed, long range, interface for group 4 +highspeedInterface.type = SimpleBroadcastInterface +highspeedInterface.transmitSpeed = 10M +highspeedInterface.transmitRange = 10 + +# Define 6 different node groups +Scenario.nrofHostGroups = 6 + +## Group-specific settings: +# groupID : Group's identifier. Used as the prefix of host names +# nrofHosts: number of hosts in the group +# movementModel: movement model of the hosts (valid class name from movement package) +# waitTime: minimum and maximum wait times (seconds) after reaching destination +# speed: minimum and maximum speeds (m/s) when moving on a path +# bufferSize: size of the message buffer (bytes) +# router: router used to route messages (valid class name from routing package) +# activeTimes: Time intervals when the nodes in the group are active (start1, end1, start2, end2, ...) +# msgTtl : TTL (minutes) of the messages created by this host group, default=infinite + +## Group and movement model specific settings +# pois: Points Of Interest indexes and probabilities (poiIndex1, poiProb1, poiIndex2, poiProb2, ... ) +# for ShortestPathMapBasedMovement +# okMaps : which map nodes are OK for the group (map file indexes), default=all +# for all MapBasedMovent models +# routeFile: route's file path - for MapRouteMovement +# routeType: route's type - for MapRouteMovement + + +# Common settings for all groups +Group.movementModel = ShortestPathMapBasedMovement +Group.router = EpidemicRouter +Group.bufferSize = 5M +Group.waitTime = 0, 120 +# All nodes have the bluetooth interface +Group.nrofInterfaces = 1 +Group.interface1 = btInterface +# Walking speeds +Group.speed = 0.5, 1.5 +# Message TTL of 300 minutes (5 hours) +Group.msgTtl = 300 + +Group.nrofHosts = 40 + +# group1 (pedestrians) specific settings +Group1.groupID = p + +# group2 specific settings +Group2.groupID = c +# cars can drive only on roads +Group2.okMaps = 1 +# 10-50 km/h +Group2.speed = 2.7, 13.9 + +# another group of pedestrians +Group3.groupID = w + +# The Tram groups +Group4.groupID = t +Group4.bufferSize = 50M +Group4.movementModel = MapRouteMovement +Group4.routeFile = data/tram3.wkt +Group4.routeType = 1 +Group4.waitTime = 10, 30 +Group4.speed = 7, 10 +Group4.nrofHosts = 2 +Group4.nrofInterfaces = 2 +Group4.interface1 = btInterface +Group4.interface2 = highspeedInterface + +Group5.groupID = t +Group5.bufferSize = 50M +Group5.movementModel = MapRouteMovement +Group5.routeFile = data/tram4.wkt +Group5.routeType = 2 +Group5.waitTime = 10, 30 +Group5.speed = 7, 10 +Group5.nrofHosts = 2 + +Group6.groupID = t +Group6.bufferSize = 50M +Group6.movementModel = MapRouteMovement +Group6.routeFile = data/tram10.wkt +Group6.routeType = 2 +Group6.waitTime = 10, 30 +Group6.speed = 7, 10 +Group6.nrofHosts = 2 + + +## Message creation parameters +# How many event generators +Events.nrof = 1 +# Class of the first event generator +Events1.class = MessageEventGenerator +# (following settings are specific for the MessageEventGenerator class) +# Creation interval in seconds (one new message every 25 to 35 seconds) +Events1.interval = 25,35 +# Message sizes (500kB - 1MB) +Events1.size = 500k,1M +# range of message source/destination addresses +Events1.hosts = 0,125 +# Message ID prefix +Events1.prefix = M + + +## Movement model settings +# seed for movement models' pseudo random number generator (default = 0) +MovementModel.rngSeed = 1 +# World's size for Movement Models without implicit size (width, height; meters) +MovementModel.worldSize = 4500, 3400 +# How long time to move hosts in the world before real simulation +MovementModel.warmup = 1000 + +## Map based movement -movement model specific settings +MapBasedMovement.nrofMapFiles = 4 + +MapBasedMovement.mapFile1 = data/roads.wkt +MapBasedMovement.mapFile2 = data/main_roads.wkt +MapBasedMovement.mapFile3 = data/pedestrian_paths.wkt +MapBasedMovement.mapFile4 = data/shops.wkt + +## Reports - all report names have to be valid report classes + +# how many reports to load +Report.nrofReports = 2 +# length of the warm up period (simulated seconds) +Report.warmup = 0 +# default directory of reports (can be overridden per Report with output setting) +Report.reportDir = reports/ +# Report classes to load +Report.report1 = ContactTimesReport +Report.report2 = ConnectivityONEReport + +## Default settings for some routers settings +ProphetRouter.secondsInTimeUnit = 30 +SprayAndWaitRouter.nrofCopies = 6 +SprayAndWaitRouter.binaryMode = true + +## Optimization settings -- these affect the speed of the simulation +## see World class for details. +Optimization.cellSizeMult = 5 +Optimization.randomizeUpdateOrder = true + + +## GUI settings + +# GUI underlay image settings +GUI.UnderlayImage.fileName = data/helsinki_underlay.png +# Image offset in pixels (x, y) +GUI.UnderlayImage.offset = 64, 20 +# Scaling factor for the image +GUI.UnderlayImage.scale = 4.75 +# Image rotation (radians) +GUI.UnderlayImage.rotate = -0.015 + +# how many events to show in the log panel (default = 30) +GUI.EventLogPanel.nrofEvents = 100 +# Regular Expression log filter (see Pattern-class from the Java API for RE-matching details) +#GUI.EventLogPanel.REfilter = .*p[1-9]<->p[1-9]$ diff --git a/example_settings/cluster_settings.txt b/example_settings/cluster_settings.txt index 19d63d6e0..8d3d22f72 100644 --- a/example_settings/cluster_settings.txt +++ b/example_settings/cluster_settings.txt @@ -59,7 +59,7 @@ MapBasedMovement.mapFile1 = data/cluster/ferryroute.wkt MapBasedMovement.mapFile2 = data/cluster/origin.wkt -## Message creation parameters +## Message creation parameters # How many event generators Events.nrof = 1 # Class of the first event generator @@ -113,4 +113,4 @@ GUI.UnderlayImage.rotate = -0.015 # how many events to show in the log panel (default = 30) GUI.EventLogPanel.nrofEvents = 30 # Regular Expression log filter (see Pattern-class from the Java API for RE-matching details) -#GUI.EventLogPanel.REfilter = .*p[1-9]<->p[1-9]$ \ No newline at end of file +#GUI.EventLogPanel.REfilter = .*p[1-9]<->p[1-9]$ diff --git a/example_settings/epidemic_settings.txt b/example_settings/epidemic_settings.txt index d96abb044..64fcce0dd 100644 --- a/example_settings/epidemic_settings.txt +++ b/example_settings/epidemic_settings.txt @@ -1,2 +1,2 @@ -Scenario.name = Epidemic -Group.router = EpidemicRouter \ No newline at end of file +Scenario.name = Epidemic +Group.router = EpidemicRouter diff --git a/example_settings/ping_app_settings.txt b/example_settings/ping_app_settings.txt index 30019c37b..39acdba32 100644 --- a/example_settings/ping_app_settings.txt +++ b/example_settings/ping_app_settings.txt @@ -1,19 +1,19 @@ -# This configuration file adds Ping application for all the nodes and -# a report module that counts the number of pings & pongs sent & received - -# Define new application -pingApp.type = PingApplication -pingApp.interval = 500 -pingApp.destinationRange = 0,125 -pingApp.pingSize = 5 -pingApp.pongSize = 5 -pingApp.passive = false - -# Set Ping app for all nodes -Group.nrofApplications = 1 -Group.application1 = pingApp - -# Add report for Ping app -Report.nrofReports = 2 -Report.report2 = PingAppReporter - +# This configuration file adds Ping application for all the nodes and +# a report module that counts the number of pings & pongs sent & received + +# Define new application +pingApp.type = PingApplication +pingApp.interval = 500 +pingApp.destinationRange = 0,125 +pingApp.pingSize = 5 +pingApp.pongSize = 5 +pingApp.passive = false + +# Set Ping app for all nodes +Group.nrofApplications = 1 +Group.application1 = pingApp + +# Add report for Ping app +Report.nrofReports = 2 +Report.report2 = PingAppReporter + diff --git a/example_settings/prophet_settings.txt b/example_settings/prophet_settings.txt index 8ecd25aa2..3ded6df0c 100644 --- a/example_settings/prophet_settings.txt +++ b/example_settings/prophet_settings.txt @@ -1,18 +1,18 @@ -## Test scenario using Prophet router and Points of Interest (POIs) - -Scenario.name = PRoPHET-%%ProphetRouter.secondsInTimeUnit%%siu -Group.router = ProphetRouter - -ProphetRouter.secondsInTimeUnit = 30 - -# Define POI data files -PointsOfInterest.poiFile1 = data/ParkPOIs.wkt -PointsOfInterest.poiFile2 = data/CentralPOIs.wkt -PointsOfInterest.poiFile3 = data/WestPOIs.wkt -PointsOfInterest.poiFile4 = data/shops.wkt - -# Define probabilities for different groups selecting POIs from different POI files -Group1.pois = 1,0.3, 2,0.1, 3,0.1, 4, 0.1 -Group2.pois = 2,0.3, 3,0.1 -Group3.pois = 3,0.3, 2,0.1, 1,0.1, 4, 0.1 -Group4.pois = 4,0.3, 2,0.1, 3,0.1, 1, 0.1 +## Test scenario using Prophet router and Points of Interest (POIs) + +Scenario.name = PRoPHET-%%ProphetRouter.secondsInTimeUnit%%siu +Group.router = ProphetRouter + +ProphetRouter.secondsInTimeUnit = 30 + +# Define POI data files +PointsOfInterest.poiFile1 = data/ParkPOIs.wkt +PointsOfInterest.poiFile2 = data/CentralPOIs.wkt +PointsOfInterest.poiFile3 = data/WestPOIs.wkt +PointsOfInterest.poiFile4 = data/shops.wkt + +# Define probabilities for different groups selecting POIs from different POI files +Group1.pois = 1,0.3, 2,0.1, 3,0.1, 4, 0.1 +Group2.pois = 2,0.3, 3,0.1 +Group3.pois = 3,0.3, 2,0.1, 1,0.1, 4, 0.1 +Group4.pois = 4,0.3, 2,0.1, 3,0.1, 1, 0.1 diff --git a/example_settings/snw_settings.txt b/example_settings/snw_settings.txt index d231f36fe..a62007917 100644 --- a/example_settings/snw_settings.txt +++ b/example_settings/snw_settings.txt @@ -1,4 +1,4 @@ -Scenario.name = SprayAndWait -Group.router = SprayAndWaitRouter -SprayAndWaitRouter.nrofCopies = 10 -SprayAndWaitRouter.binaryMode = true +Scenario.name = SprayAndWait +Group.router = SprayAndWaitRouter +SprayAndWaitRouter.nrofCopies = 10 +SprayAndWaitRouter.binaryMode = true diff --git a/example_settings/wlan-interface.txt b/example_settings/wlan-interface.txt index bc4fcd4b0..45f30959c 100644 --- a/example_settings/wlan-interface.txt +++ b/example_settings/wlan-interface.txt @@ -11,4 +11,4 @@ wlanInterface.transmitRange = 91 # dummy speed wlanInterface.transmitSpeed = 0 -Group.interface1 = wlanInterface \ No newline at end of file +Group.interface1 = wlanInterface diff --git a/gui/DTNSimGUI.java b/gui/DTNSimGUI.java index d1d78a3cb..985f00615 100644 --- a/gui/DTNSimGUI.java +++ b/gui/DTNSimGUI.java @@ -1,336 +1,336 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package gui; - -import gui.playfield.PlayField; - -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.lang.reflect.InvocationTargetException; - -import javax.swing.JOptionPane; -import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; - -import movement.Path; -import ui.DTNSimUI; -import core.Coord; -import core.DTNHost; -import core.SimClock; - -/** - * Graphical User Interface for simulator - */ -public class DTNSimGUI extends DTNSimUI { - private MainWindow main; - private PlayField field; - private GUIControls guiControls; - private EventLogPanel eventLogPanel; - private InfoPanel infoPanel; - - private void startGUI() { - try { - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - try { - initGUI(); - } catch (AssertionError e) { - processAssertionError(e); - } - } - }); - } catch (InterruptedException e) { - e.printStackTrace(); - System.exit(-1); - } catch (InvocationTargetException e) { - e.printStackTrace(); - System.exit(-1); - } - } - - /** - * Initializes the GUI - */ - private void initGUI() { - this.field = new PlayField(world, this); - - this.field.addMouseListener(new PlayfieldMouseHandler()); - this.field.addMouseWheelListener(new PlayfieldMouseHandler()); - - this.guiControls = new GUIControls(this,this.field); - this.eventLogPanel = new EventLogPanel(this); - this.infoPanel = new InfoPanel(this); - this.main = new MainWindow(this.scen.getName(), world, field, - guiControls, infoPanel, eventLogPanel, this); - - scen.addMessageListener(eventLogPanel); - scen.addConnectionListener(eventLogPanel); - - if (scen.getMap() != null ) { - field.setMap(scen.getMap()); - } - - // if user closes the main window, call closeSim() - this.main.addWindowListener(new WindowAdapter() { - private boolean closeAgain = false; - public void windowClosing(WindowEvent e) { - closeSim(); - if (closeAgain) { - // if method is called again, force closing - System.err.println("Forced close. "+ - "Some reports may have not been finalized."); - System.exit(-1); - } - closeAgain = true; - } - }); - - this.main.setVisible(true); - } - - @Override - protected void runSim() { - double simTime = SimClock.getTime(); - double endTime = scen.getEndTime(); - - startGUI(); - - // Startup DTN2Manager - // XXX: Would be nice if this wasn't needed.. - // DTN2Manager.setup(world); - - while (simTime < endTime && !simCancelled){ - if (guiControls.isPaused()) { - wait(10); // release CPU resources when paused - } - else { - try { - world.update(); - } catch (AssertionError e) { - // handles both assertion errors and SimErrors - processAssertionError(e); - } - simTime = SimClock.getTime(); - } - this.update(false); - } - - simDone = true; - done(); - this.update(true); // force final GUI update - - if (!simCancelled) { // NOT cancelled -> leave the GUI running - JOptionPane.showMessageDialog(getParentFrame(), - "Simulation done"); - } - else { // was cancelled -> exit immediately - System.exit(0); - } - } - - /** - * Processes assertion errors by showing a warning dialog to the user - * and pausing the simulation (if it's running) - * @param e The error that was thrown - */ - private void processAssertionError(AssertionError e) { - String title = e.getClass().getSimpleName() + " (simulation paused)"; - String msg = e.getMessage(); - String txt = (msg != null ? msg : "") + " at simtime " + - SimClock.getIntTime() + "\n\ncaught at:\n" + - e.getStackTrace()[0].toString() + - "\nNote that the simulation might be in inconsistent state, "+ - "continue only with caution.\n\n Show rest of the stack trace?"; - // rest of the update cycle that caused the exception is skipped - // so the user is warned about the consequences - - - if (guiControls != null) { - guiControls.setPaused(true); - } - - int selection = JOptionPane.showOptionDialog(getParentFrame(), txt, - title, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, - null, null, null); - - if (selection == 0) { - txt = ""; - for (StackTraceElement trace : e.getStackTrace()) { - txt += trace.toString()+"\n"; - } - JOptionPane.showMessageDialog(getParentFrame(), txt, - "stack trace", JOptionPane.INFORMATION_MESSAGE); - } - } - - - - /** - * Closes the program if simulation is done or cancels it. - */ - public void closeSim() { - if (simDone) { - System.exit(0); - } - this.world.cancelSim(); - this.simCancelled = true; - } - - /** - * Updates the GUI - */ - public void update(boolean forcedUpdate) { - double guiUpdateInterval = guiControls.getUpdateInterval(); - - // update only if long enough simTime has passed (and not forced) - if (!forcedUpdate && guiUpdateInterval > (SimClock.getTime() - - this.lastUpdate)) { - return; - } - - try { - // run update in EDT, TODO: optimize threading - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - updateView(); - } - }); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - - // wait a while if we don't want to run simulation at full speed - if (guiUpdateInterval < 0) { - wait(100*(int)(-guiUpdateInterval)); - } - - } - - /** - * Updates playfield and sim time field - * - */ - private void updateView() { - double simTime = SimClock.getTime(); - this.lastUpdate = simTime; - guiControls.setSimTime(simTime); //update time to control panel - - this.field.updateField(); - } - - /** - * Sets the pause of the simulation on/off - * @param paused True if pause should be set on - */ - public void setPaused(boolean paused) { - this.guiControls.setPaused(paused); - } - - /** - * Sets a node's graphical presentation in the center of the playfield view - * @param host The node to center - */ - public void setFocus(DTNHost host) { - centerViewAt(host.getLocation()); - infoPanel.showInfo(host); - showPath(host.getPath()); // show path on the playfield - } - - /** - * Shows a path on the playfield - * @param path The path to show - */ - public void showPath(Path path) { - field.addPath(path); - } - - /** - * Returns the world coordinates that are currently in the center - * of the viewport - * @return The coordinates - */ - public Coord getCenterViewCoord() { - JScrollPane sp = main.getPlayFieldScroll(); - double midX, midY; - - midX = sp.getHorizontalScrollBar().getValue() + - sp.getViewport().getWidth()/2; - midY = sp.getVerticalScrollBar().getValue() + - sp.getViewport().getHeight()/2; - - return this.field.getWorldPosition(new Coord(midX, midY)); - } - - /** - * Sets certain location to be in the center of the playfield view - * @param loc The location to center - */ - public void centerViewAt(Coord loc) { - JScrollPane sp = main.getPlayFieldScroll(); - Coord gLoc = this.field.getGraphicsPosition(loc); - int midX, midY; - - updateView(); // update graphics to match the values - - midX = (int)gLoc.getX() - sp.getViewport().getWidth()/2; - midY = (int)gLoc.getY() - sp.getViewport().getHeight()/2; - - sp.getHorizontalScrollBar().setValue(midX); - sp.getVerticalScrollBar().setValue(midY); - } - - /** - * Returns the info panel of the GUI - * @return the info panel of the GUI - */ - public InfoPanel getInfoPanel() { - return this.infoPanel; - } - - /** - * Returns the parent frame (window) of the gui. - * @return The parent frame - */ - public MainWindow getParentFrame() { - return this.main; - } - - /** - * Suspend thread for ms milliseconds - * @param ms The nrof milliseconds to wait - */ - private void wait(int ms) { - try { - Thread.sleep(ms); - } catch (InterruptedException e) { - // nothing to do here - } - } - - /** - * Handler for playfield's mouse clicks. - */ - private class PlayfieldMouseHandler extends MouseAdapter implements - MouseWheelListener { - /** - * If mouse button is clicked, centers view at that location. - */ - public void mouseClicked(MouseEvent e) { - - java.awt.Point p = e.getPoint(); - centerViewAt(field.getWorldPosition(new Coord(p.x, p.y))); - } - - public void mouseWheelMoved(java.awt.event.MouseWheelEvent e) { - guiControls.changeZoom(e.getWheelRotation()); - } - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui; + +import gui.playfield.PlayField; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; + +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +import movement.Path; +import ui.DTNSimUI; +import core.Coord; +import core.DTNHost; +import core.SimClock; + +/** + * Graphical User Interface for simulator + */ +public class DTNSimGUI extends DTNSimUI { + private MainWindow main; + private PlayField field; + private GUIControls guiControls; + private EventLogPanel eventLogPanel; + private InfoPanel infoPanel; + + private void startGUI() { + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + try { + initGUI(); + } catch (AssertionError e) { + processAssertionError(e); + } + } + }); + } catch (InterruptedException e) { + e.printStackTrace(); + System.exit(-1); + } catch (InvocationTargetException e) { + e.printStackTrace(); + System.exit(-1); + } + } + + /** + * Initializes the GUI + */ + private void initGUI() { + this.field = new PlayField(world, this); + + this.field.addMouseListener(new PlayfieldMouseHandler()); + this.field.addMouseWheelListener(new PlayfieldMouseHandler()); + + this.guiControls = new GUIControls(this,this.field); + this.eventLogPanel = new EventLogPanel(this); + this.infoPanel = new InfoPanel(this); + this.main = new MainWindow(this.scen.getName(), world, field, + guiControls, infoPanel, eventLogPanel, this); + + scen.addMessageListener(eventLogPanel); + scen.addConnectionListener(eventLogPanel); + + if (scen.getMap() != null ) { + field.setMap(scen.getMap()); + } + + // if user closes the main window, call closeSim() + this.main.addWindowListener(new WindowAdapter() { + private boolean closeAgain = false; + public void windowClosing(WindowEvent e) { + closeSim(); + if (closeAgain) { + // if method is called again, force closing + System.err.println("Forced close. "+ + "Some reports may have not been finalized."); + System.exit(-1); + } + closeAgain = true; + } + }); + + this.main.setVisible(true); + } + + @Override + protected void runSim() { + double simTime = SimClock.getTime(); + double endTime = scen.getEndTime(); + + startGUI(); + + // Startup DTN2Manager + // XXX: Would be nice if this wasn't needed.. + // DTN2Manager.setup(world); + + while (simTime < endTime && !simCancelled){ + if (guiControls.isPaused()) { + wait(10); // release CPU resources when paused + } + else { + try { + world.update(); + } catch (AssertionError e) { + // handles both assertion errors and SimErrors + processAssertionError(e); + } + simTime = SimClock.getTime(); + } + this.update(false); + } + + simDone = true; + done(); + this.update(true); // force final GUI update + + if (!simCancelled) { // NOT cancelled -> leave the GUI running + JOptionPane.showMessageDialog(getParentFrame(), + "Simulation done"); + } + else { // was cancelled -> exit immediately + System.exit(0); + } + } + + /** + * Processes assertion errors by showing a warning dialog to the user + * and pausing the simulation (if it's running) + * @param e The error that was thrown + */ + private void processAssertionError(AssertionError e) { + String title = e.getClass().getSimpleName() + " (simulation paused)"; + String msg = e.getMessage(); + String txt = (msg != null ? msg : "") + " at simtime " + + SimClock.getIntTime() + "\n\ncaught at:\n" + + e.getStackTrace()[0].toString() + + "\nNote that the simulation might be in inconsistent state, "+ + "continue only with caution.\n\n Show rest of the stack trace?"; + // rest of the update cycle that caused the exception is skipped + // so the user is warned about the consequences + + + if (guiControls != null) { + guiControls.setPaused(true); + } + + int selection = JOptionPane.showOptionDialog(getParentFrame(), txt, + title, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, + null, null, null); + + if (selection == 0) { + txt = ""; + for (StackTraceElement trace : e.getStackTrace()) { + txt += trace.toString()+"\n"; + } + JOptionPane.showMessageDialog(getParentFrame(), txt, + "stack trace", JOptionPane.INFORMATION_MESSAGE); + } + } + + + + /** + * Closes the program if simulation is done or cancels it. + */ + public void closeSim() { + if (simDone) { + System.exit(0); + } + this.world.cancelSim(); + this.simCancelled = true; + } + + /** + * Updates the GUI + */ + public void update(boolean forcedUpdate) { + double guiUpdateInterval = guiControls.getUpdateInterval(); + + // update only if long enough simTime has passed (and not forced) + if (!forcedUpdate && guiUpdateInterval > (SimClock.getTime() + - this.lastUpdate)) { + return; + } + + try { + // run update in EDT, TODO: optimize threading + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + updateView(); + } + }); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + + // wait a while if we don't want to run simulation at full speed + if (guiUpdateInterval < 0) { + wait(100*(int)(-guiUpdateInterval)); + } + + } + + /** + * Updates playfield and sim time field + * + */ + private void updateView() { + double simTime = SimClock.getTime(); + this.lastUpdate = simTime; + guiControls.setSimTime(simTime); //update time to control panel + + this.field.updateField(); + } + + /** + * Sets the pause of the simulation on/off + * @param paused True if pause should be set on + */ + public void setPaused(boolean paused) { + this.guiControls.setPaused(paused); + } + + /** + * Sets a node's graphical presentation in the center of the playfield view + * @param host The node to center + */ + public void setFocus(DTNHost host) { + centerViewAt(host.getLocation()); + infoPanel.showInfo(host); + showPath(host.getPath()); // show path on the playfield + } + + /** + * Shows a path on the playfield + * @param path The path to show + */ + public void showPath(Path path) { + field.addPath(path); + } + + /** + * Returns the world coordinates that are currently in the center + * of the viewport + * @return The coordinates + */ + public Coord getCenterViewCoord() { + JScrollPane sp = main.getPlayFieldScroll(); + double midX, midY; + + midX = sp.getHorizontalScrollBar().getValue() + + sp.getViewport().getWidth()/2; + midY = sp.getVerticalScrollBar().getValue() + + sp.getViewport().getHeight()/2; + + return this.field.getWorldPosition(new Coord(midX, midY)); + } + + /** + * Sets certain location to be in the center of the playfield view + * @param loc The location to center + */ + public void centerViewAt(Coord loc) { + JScrollPane sp = main.getPlayFieldScroll(); + Coord gLoc = this.field.getGraphicsPosition(loc); + int midX, midY; + + updateView(); // update graphics to match the values + + midX = (int)gLoc.getX() - sp.getViewport().getWidth()/2; + midY = (int)gLoc.getY() - sp.getViewport().getHeight()/2; + + sp.getHorizontalScrollBar().setValue(midX); + sp.getVerticalScrollBar().setValue(midY); + } + + /** + * Returns the info panel of the GUI + * @return the info panel of the GUI + */ + public InfoPanel getInfoPanel() { + return this.infoPanel; + } + + /** + * Returns the parent frame (window) of the gui. + * @return The parent frame + */ + public MainWindow getParentFrame() { + return this.main; + } + + /** + * Suspend thread for ms milliseconds + * @param ms The nrof milliseconds to wait + */ + private void wait(int ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + // nothing to do here + } + } + + /** + * Handler for playfield's mouse clicks. + */ + private class PlayfieldMouseHandler extends MouseAdapter implements + MouseWheelListener { + /** + * If mouse button is clicked, centers view at that location. + */ + public void mouseClicked(MouseEvent e) { + + java.awt.Point p = e.getPoint(); + centerViewAt(field.getWorldPosition(new Coord(p.x, p.y))); + } + + public void mouseWheelMoved(java.awt.event.MouseWheelEvent e) { + guiControls.changeZoom(e.getWheelRotation()); + } + } + +} diff --git a/gui/EventLogControl.java b/gui/EventLogControl.java index f5ffa4145..42914026c 100644 --- a/gui/EventLogControl.java +++ b/gui/EventLogControl.java @@ -1,64 +1,64 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui; - +package gui; + import javax.swing.JCheckBox; - -/** - * Class capsulates the references to the controls one can add to - * the EventLogControlPanel - * - */ -public class EventLogControl { - private JCheckBox show; - private JCheckBox pause; - - /** - * Constructor. - * @param show The checkbox that controls showing this type of event - * @param pause The checkbox that controls pausing on this type of event - */ - public EventLogControl(JCheckBox show, JCheckBox pause) { - this.show = show; - this.pause = pause; - } - - /** - * Returns true if this event type should be shown - * @return true if this event type should be shown - */ - public boolean showEvent() { - return this.show.isSelected(); - } - - /** - * Returns true if this event type should cause pause - * @return true if this event type should cause pause - */ - - public boolean pauseOnEvent() { - return this.pause.isSelected(); - } - - /** - * Sets ought this event type should be shown (return true for - * {@link #showEvent()} ) - * @param show If true, events are set to be shown - */ - public void setShowEvent(boolean show) { - this.show.setSelected(show); - } - - /** - * Sets ought this event type cause pause (return true for - * {@link #pauseOnEvent()} ) - * @param pause If true, events cause pause - */ - public void setPauseOnEvent(boolean pause) { - this.pause.setSelected(pause); - } - - -} + +/** + * Class capsulates the references to the controls one can add to + * the EventLogControlPanel + * + */ +public class EventLogControl { + private JCheckBox show; + private JCheckBox pause; + + /** + * Constructor. + * @param show The checkbox that controls showing this type of event + * @param pause The checkbox that controls pausing on this type of event + */ + public EventLogControl(JCheckBox show, JCheckBox pause) { + this.show = show; + this.pause = pause; + } + + /** + * Returns true if this event type should be shown + * @return true if this event type should be shown + */ + public boolean showEvent() { + return this.show.isSelected(); + } + + /** + * Returns true if this event type should cause pause + * @return true if this event type should cause pause + */ + + public boolean pauseOnEvent() { + return this.pause.isSelected(); + } + + /** + * Sets ought this event type should be shown (return true for + * {@link #showEvent()} ) + * @param show If true, events are set to be shown + */ + public void setShowEvent(boolean show) { + this.show.setSelected(show); + } + + /** + * Sets ought this event type cause pause (return true for + * {@link #pauseOnEvent()} ) + * @param pause If true, events cause pause + */ + public void setPauseOnEvent(boolean pause) { + this.pause.setSelected(pause); + } + + +} diff --git a/gui/EventLogControlPanel.java b/gui/EventLogControlPanel.java index 43968b78c..70940632e 100644 --- a/gui/EventLogControlPanel.java +++ b/gui/EventLogControlPanel.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui; - +package gui; + import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; @@ -16,144 +16,144 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; - -/** - * Control panel for event log - * - */ -public class EventLogControlPanel extends JPanel implements ActionListener { - private static final String TITLE_TEXT = "Event log controls"; - private static final String SHOW_TEXT = "show"; - private static final String PAUSE_TEXT = "pause"; - private static final int PADDING = 5; - private Font smallFont = new Font("sans",Font.PLAIN,11); - private Font headingFont = new Font("sans",Font.BOLD,11); - private Vector logControls; - - private JCheckBox showAllCheck; - private JCheckBox pauseAllCheck; - - private GridBagLayout layout; - private GridBagConstraints c; - - /** - * Constructor. Creates a new control panel. - */ - public EventLogControlPanel() { - layout = new GridBagLayout(); - c = new GridBagConstraints(); - logControls = new Vector(); - - c.ipadx = PADDING; - - setLayout(layout); - this.setBorder(BorderFactory.createTitledBorder( - getBorder(), TITLE_TEXT)); - - c.fill = GridBagConstraints.BOTH; - addLabel(" "); - addLabel(SHOW_TEXT + ""); - c.gridwidth = GridBagConstraints.REMAINDER; //end row - addLabel(PAUSE_TEXT); - - // create "show/pause on all selections - c.gridwidth = 1; - addLabel("all"); - showAllCheck = addCheckBox(true,false); - pauseAllCheck = addCheckBox(false,true); - showAllCheck.addActionListener(this); - pauseAllCheck.addActionListener(this); - - this.setMinimumSize(new Dimension(0,0)); - } - - /** - * Adds a new filter&pause control - * @param name Name of the control - * @param showOn Is "show" initially selected - * @param pauseOn Is "pause" initially selected - * @return Event log control object that can be queried for status - */ - public EventLogControl addControl(String name, boolean showOn, - boolean pauseOn) { - JCheckBox filterCheck; - JCheckBox pauseCheck; - EventLogControl control; - - c.gridwidth = 1; // one component/cell - addLabel(name); - filterCheck = addCheckBox(showOn, false); - pauseCheck = addCheckBox(pauseOn, true); - - control = new EventLogControl(filterCheck, pauseCheck); - this.logControls.add(control); - return control; - } - - /** - * Creates and adds a new checkbox to this panel - * @param selected Is the checkbox initially selected - * @param endOfRow Is the box last in the row in the layout - * @return The created checkbox - */ - private JCheckBox addCheckBox(boolean selected, boolean endOfRow) { - JCheckBox box = new JCheckBox(); - box.setSelected(selected); - - if (endOfRow) { - c.gridwidth = GridBagConstraints.REMAINDER; // use rest of the line - } - else { - c.gridwidth = 1; // default - } - - layout.setConstraints(box, c); - add(box); - - return box; - } - - /** - * Adds a new filter&pause control with initially "show" checked - * but "pause" unchecked - * @param name Name of the control - * @return Event log control object that can be queried for status - * @see #addControl(String name, boolean showOn, boolean pauseOn) - */ - public EventLogControl addControl(String name) { - return addControl(name, true, false); - } - - /** - * Adds a new heading in the control panel. Subsequent addControl - * controls will be under this heading - * @param name The heading text - */ - public void addHeading(String name) { - c.gridwidth = GridBagConstraints.REMAINDER; - addLabel(name).setFont(this.headingFont); - } - - private JLabel addLabel(String txt) { - JLabel label = new JLabel(txt); - label.setFont(this.smallFont); - layout.setConstraints(label, c); - add(label); - return label; - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == this.showAllCheck) { - for (EventLogControl elc : logControls) { - elc.setShowEvent(this.showAllCheck.isSelected()); - } - } - else if (e.getSource() == this.pauseAllCheck) { - for (EventLogControl elc : logControls) { - elc.setPauseOnEvent(this.pauseAllCheck.isSelected()); - } - } - - - } -} + +/** + * Control panel for event log + * + */ +public class EventLogControlPanel extends JPanel implements ActionListener { + private static final String TITLE_TEXT = "Event log controls"; + private static final String SHOW_TEXT = "show"; + private static final String PAUSE_TEXT = "pause"; + private static final int PADDING = 5; + private Font smallFont = new Font("sans",Font.PLAIN,11); + private Font headingFont = new Font("sans",Font.BOLD,11); + private Vector logControls; + + private JCheckBox showAllCheck; + private JCheckBox pauseAllCheck; + + private GridBagLayout layout; + private GridBagConstraints c; + + /** + * Constructor. Creates a new control panel. + */ + public EventLogControlPanel() { + layout = new GridBagLayout(); + c = new GridBagConstraints(); + logControls = new Vector(); + + c.ipadx = PADDING; + + setLayout(layout); + this.setBorder(BorderFactory.createTitledBorder( + getBorder(), TITLE_TEXT)); + + c.fill = GridBagConstraints.BOTH; + addLabel(" "); + addLabel(SHOW_TEXT + ""); + c.gridwidth = GridBagConstraints.REMAINDER; //end row + addLabel(PAUSE_TEXT); + + // create "show/pause on all selections + c.gridwidth = 1; + addLabel("all"); + showAllCheck = addCheckBox(true,false); + pauseAllCheck = addCheckBox(false,true); + showAllCheck.addActionListener(this); + pauseAllCheck.addActionListener(this); + + this.setMinimumSize(new Dimension(0,0)); + } + + /** + * Adds a new filter&pause control + * @param name Name of the control + * @param showOn Is "show" initially selected + * @param pauseOn Is "pause" initially selected + * @return Event log control object that can be queried for status + */ + public EventLogControl addControl(String name, boolean showOn, + boolean pauseOn) { + JCheckBox filterCheck; + JCheckBox pauseCheck; + EventLogControl control; + + c.gridwidth = 1; // one component/cell + addLabel(name); + filterCheck = addCheckBox(showOn, false); + pauseCheck = addCheckBox(pauseOn, true); + + control = new EventLogControl(filterCheck, pauseCheck); + this.logControls.add(control); + return control; + } + + /** + * Creates and adds a new checkbox to this panel + * @param selected Is the checkbox initially selected + * @param endOfRow Is the box last in the row in the layout + * @return The created checkbox + */ + private JCheckBox addCheckBox(boolean selected, boolean endOfRow) { + JCheckBox box = new JCheckBox(); + box.setSelected(selected); + + if (endOfRow) { + c.gridwidth = GridBagConstraints.REMAINDER; // use rest of the line + } + else { + c.gridwidth = 1; // default + } + + layout.setConstraints(box, c); + add(box); + + return box; + } + + /** + * Adds a new filter&pause control with initially "show" checked + * but "pause" unchecked + * @param name Name of the control + * @return Event log control object that can be queried for status + * @see #addControl(String name, boolean showOn, boolean pauseOn) + */ + public EventLogControl addControl(String name) { + return addControl(name, true, false); + } + + /** + * Adds a new heading in the control panel. Subsequent addControl + * controls will be under this heading + * @param name The heading text + */ + public void addHeading(String name) { + c.gridwidth = GridBagConstraints.REMAINDER; + addLabel(name).setFont(this.headingFont); + } + + private JLabel addLabel(String txt) { + JLabel label = new JLabel(txt); + label.setFont(this.smallFont); + layout.setConstraints(label, c); + add(label); + return label; + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == this.showAllCheck) { + for (EventLogControl elc : logControls) { + elc.setShowEvent(this.showAllCheck.isSelected()); + } + } + else if (e.getSource() == this.pauseAllCheck) { + for (EventLogControl elc : logControls) { + elc.setPauseOnEvent(this.pauseAllCheck.isSelected()); + } + } + + + } +} diff --git a/gui/EventLogPanel.java b/gui/EventLogPanel.java index 2ada1ed67..f94c7faf2 100644 --- a/gui/EventLogPanel.java +++ b/gui/EventLogPanel.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui; - +package gui; + import java.awt.Color; import java.awt.Font; import java.awt.GridLayout; @@ -25,308 +25,308 @@ import core.MessageListener; import core.Settings; import core.SimClock; - -/** - * Event log panel where log entries are displayed. - */ -public class EventLogPanel extends JPanel - implements ConnectionListener, MessageListener, ActionListener { + +/** + * Event log panel where log entries are displayed. + */ +public class EventLogPanel extends JPanel + implements ConnectionListener, MessageListener, ActionListener { /** Event log panel settings namespace ({@value}) */ public static final String EL_PANEL_NS = "GUI.EventLogPanel"; - + /** Number of events -setting id ({@value}). Defines the number of * events to show in the panel. */ public static final String NROF_EVENTS_S = "nrofEvents"; - + /** Regular expression filter -setting id ({@value}). Defines the regular * expression against which the event texts are matched; only matching * events are not shown */ public static final String EVENTS_RE_S = "REfilter"; - - private static final String PANEL_TITLE = "Event log"; - /** format of a single log entry */ - private static final String ENTRY_FORMAT = "% 9.1f: %s "; - private static final int FONT_SIZE = 12; - private static final String FONT_TYPE = "monospaced"; - private static final Color LOG_BUTTON_BG = Color.WHITE; + + private static final String PANEL_TITLE = "Event log"; + /** format of a single log entry */ + private static final String ENTRY_FORMAT = "% 9.1f: %s "; + private static final int FONT_SIZE = 12; + private static final String FONT_TYPE = "monospaced"; + private static final Color LOG_BUTTON_BG = Color.WHITE; private static final String HOST_DELIM = "<->"; - private static final Color HIGHLIGHT_BG_COLOR = Color.GREEN; - - // constants used for button property - private static final String HOST_PROP = "host"; - private static final String MSG_PROP = "message"; - - /** How often the log is updated (milliseconds) */ - public static final int LOG_UP_INTERVAL = 500; - - /** Regular expression to filter log entries (changed trough Settings) */ + private static final Color HIGHLIGHT_BG_COLOR = Color.GREEN; + + // constants used for button property + private static final String HOST_PROP = "host"; + private static final String MSG_PROP = "message"; + + /** How often the log is updated (milliseconds) */ + public static final int LOG_UP_INTERVAL = 500; + + /** Regular expression to filter log entries (changed trough Settings) */ private String regExp = null; - public static final int DEFAULT_MAX_NROF_EVENTS = 30; - /** how many events to show in log (changed trough Settings) */ - private int maxNrofEvents; - - private Font font; // font used in log entries - private DTNSimGUI gui; - private Vector eventPanes; - private GridLayout layout; - - private EventLogControlPanel controls; - private EventLogControl conUpCheck; - private EventLogControl conDownCheck; - private EventLogControl msgCreateCheck; - private EventLogControl msgTransferStartCheck; - private EventLogControl msgRelayCheck; - private EventLogControl msgRemoveCheck; - private EventLogControl msgDeliveredCheck; - private EventLogControl msgDropCheck; - private EventLogControl msgAbortCheck; - - /** - * Creates a new log panel - * @param gui The where this log belongs to (for callbacks) - */ - public EventLogPanel(DTNSimGUI gui) { - this.gui = gui; - String title = PANEL_TITLE; - Settings s = new Settings(EL_PANEL_NS); - + public static final int DEFAULT_MAX_NROF_EVENTS = 30; + /** how many events to show in log (changed trough Settings) */ + private int maxNrofEvents; + + private Font font; // font used in log entries + private DTNSimGUI gui; + private Vector eventPanes; + private GridLayout layout; + + private EventLogControlPanel controls; + private EventLogControl conUpCheck; + private EventLogControl conDownCheck; + private EventLogControl msgCreateCheck; + private EventLogControl msgTransferStartCheck; + private EventLogControl msgRelayCheck; + private EventLogControl msgRemoveCheck; + private EventLogControl msgDeliveredCheck; + private EventLogControl msgDropCheck; + private EventLogControl msgAbortCheck; + + /** + * Creates a new log panel + * @param gui The where this log belongs to (for callbacks) + */ + public EventLogPanel(DTNSimGUI gui) { + this.gui = gui; + String title = PANEL_TITLE; + Settings s = new Settings(EL_PANEL_NS); + this.maxNrofEvents = s.getInt(NROF_EVENTS_S, DEFAULT_MAX_NROF_EVENTS); - this.regExp = s.getSetting(EVENTS_RE_S, null); - - layout = new GridLayout(maxNrofEvents,1); - - this.setLayout(layout); - if (this.regExp != null) { - title += " - RE-filter: " + regExp; - } - this.setBorder(BorderFactory.createTitledBorder( - getBorder(), title)); - - this.eventPanes = new Vector(maxNrofEvents); - this.font = new Font(FONT_TYPE,Font.PLAIN, FONT_SIZE); - this.controls = createControls(); - - // set log view to update every LOG_UP_INTERVAL milliseconds - // also ensures that the update is done in Swing's EDT - ActionListener taskPerformer = new ActionListener() { - public void actionPerformed(ActionEvent evt) { - updateLogView(); - } - }; - Timer t = new Timer(LOG_UP_INTERVAL, taskPerformer); - t.start(); - } - - /** - * Creates a control panel for the log - * @return The created EventLogControls - */ - private EventLogControlPanel createControls() { - EventLogControlPanel c = new EventLogControlPanel(); - c.addHeading("connections"); - conUpCheck = c.addControl("up"); - conDownCheck = c.addControl("down"); - c.addHeading("messages"); - msgCreateCheck = c.addControl("created"); - msgTransferStartCheck = c.addControl("started relay"); - msgRelayCheck = c.addControl("relayed"); - msgDeliveredCheck = c.addControl("delivered"); - msgRemoveCheck = c.addControl("removed"); - msgDropCheck = c.addControl("dropped"); - msgAbortCheck = c.addControl("aborted"); - return c; - } - - /** - * Returns the control panel that this log uses - * @return The control panel - */ - public EventLogControlPanel getControls() { - return this.controls; - } - - /** - * Adds a new event to the event log panel - * @param description Textual description of the event - * @param host1 Host that caused the event or null if there was not any - * @param host2 Another host that was involved in the event (or null) + this.regExp = s.getSetting(EVENTS_RE_S, null); + + layout = new GridLayout(maxNrofEvents,1); + + this.setLayout(layout); + if (this.regExp != null) { + title += " - RE-filter: " + regExp; + } + this.setBorder(BorderFactory.createTitledBorder( + getBorder(), title)); + + this.eventPanes = new Vector(maxNrofEvents); + this.font = new Font(FONT_TYPE,Font.PLAIN, FONT_SIZE); + this.controls = createControls(); + + // set log view to update every LOG_UP_INTERVAL milliseconds + // also ensures that the update is done in Swing's EDT + ActionListener taskPerformer = new ActionListener() { + public void actionPerformed(ActionEvent evt) { + updateLogView(); + } + }; + Timer t = new Timer(LOG_UP_INTERVAL, taskPerformer); + t.start(); + } + + /** + * Creates a control panel for the log + * @return The created EventLogControls + */ + private EventLogControlPanel createControls() { + EventLogControlPanel c = new EventLogControlPanel(); + c.addHeading("connections"); + conUpCheck = c.addControl("up"); + conDownCheck = c.addControl("down"); + c.addHeading("messages"); + msgCreateCheck = c.addControl("created"); + msgTransferStartCheck = c.addControl("started relay"); + msgRelayCheck = c.addControl("relayed"); + msgDeliveredCheck = c.addControl("delivered"); + msgRemoveCheck = c.addControl("removed"); + msgDropCheck = c.addControl("dropped"); + msgAbortCheck = c.addControl("aborted"); + return c; + } + + /** + * Returns the control panel that this log uses + * @return The control panel + */ + public EventLogControlPanel getControls() { + return this.controls; + } + + /** + * Adds a new event to the event log panel + * @param description Textual description of the event + * @param host1 Host that caused the event or null if there was not any + * @param host2 Another host that was involved in the event (or null) * @param message Message that was involved in the event (or null) - * @param highlight If true, the log entry is highlighted - */ - private void addEvent(String description, DTNHost host1, - DTNHost host2, Message message, boolean highlight) { - JPanel eventPane = new JPanel(); - eventPane.setLayout(new BoxLayout(eventPane,BoxLayout.LINE_AXIS)); - - String text = String.format(ENTRY_FORMAT, - SimClock.getTime(),description); - JLabel label = new JLabel(text); - label.setFont(font); - eventPane.add(label); - - if (host1 != null) { - addInfoButton(eventPane,host1,HOST_PROP); - } - if (host2 != null) { - JLabel betweenLabel = new JLabel(HOST_DELIM); - betweenLabel.setFont(font); - eventPane.add(betweenLabel); - addInfoButton(eventPane,host2,HOST_PROP); - } - if (message != null) { - addInfoButton(eventPane, message, MSG_PROP); - } + * @param highlight If true, the log entry is highlighted + */ + private void addEvent(String description, DTNHost host1, + DTNHost host2, Message message, boolean highlight) { + JPanel eventPane = new JPanel(); + eventPane.setLayout(new BoxLayout(eventPane,BoxLayout.LINE_AXIS)); + + String text = String.format(ENTRY_FORMAT, + SimClock.getTime(),description); + JLabel label = new JLabel(text); + label.setFont(font); + eventPane.add(label); + + if (host1 != null) { + addInfoButton(eventPane,host1,HOST_PROP); + } + if (host2 != null) { + JLabel betweenLabel = new JLabel(HOST_DELIM); + betweenLabel.setFont(font); + eventPane.add(betweenLabel); + addInfoButton(eventPane,host2,HOST_PROP); + } + if (message != null) { + addInfoButton(eventPane, message, MSG_PROP); + } if (highlight) { eventPane.setBackground(HIGHLIGHT_BG_COLOR); } - - eventPanes.add(eventPane); - - // if the log is full, remove oldest entries first - if (this.eventPanes.size() > maxNrofEvents) { - eventPanes.remove(0); - } - } - - /** - * Updates the log view - */ - private void updateLogView() { - //TODO Optimization: Check if update is really necessary - this.removeAll(); - for (int i=0; i< this.eventPanes.size(); i++) { - this.add(eventPanes.get(i)); - } - revalidate(); - } - - - /** - * Adds a new button to a log entry panel and attaches a client - * property into it - * @param panel Panel where to add the button - * @param o Client property object to add - * @param clientProp Client property key to use for the object - */ - private void addInfoButton(JPanel panel, Object o, String clientProp) { - JButton hButton; - hButton = new JButton(o.toString()); - hButton.putClientProperty(clientProp, o); - hButton.addActionListener(this); - hButton.setFont(font); - hButton.setMargin(new Insets(0,0,0,0)); - hButton.setBackground(LOG_BUTTON_BG); - panel.add(hButton); - } - - /** - * Processes a log event - * @param check EventLogControls used to check if this entry type should - * be shown and/or paused upon - * @param name Text description of the event - * @param host1 First host involved in the event (if any, can be null) - * @param host2 Second host involved in the event (if any, can be null) - * @param message The message involved in the event (if any, can be null) - */ - private void processEvent(EventLogControl check, final String name, - final DTNHost host1, final DTNHost host2, final Message message) { - String descString; // String format description of the event - - if (!check.showEvent()) { - return; // if event's "show" is not checked, won't pause either - } - - descString = name + " " + - (host1!=null ? host1 : "") + - (host2!= null ? (HOST_DELIM + host2) : "") + - (message!=null ? " " + message : ""); - - if (regExp != null && !descString.matches(regExp)){ - return; // description doesn't match defined regular expression - } - - if (check.pauseOnEvent()) { - gui.setPaused(true); - if (host1 != null) { - gui.setFocus(host1); - } - } - - addEvent(name, host1, host2, message, check.pauseOnEvent()); - } - - // Implementations of ConnectionListener and MessageListener interfaces - public void hostsConnected(DTNHost host1, DTNHost host2) { - processEvent(conUpCheck, "Connection UP", host1, host2, null); - } - - public void hostsDisconnected(DTNHost host1, DTNHost host2) { - processEvent(conDownCheck, "Connection DOWN", host1, host2, null); - } - - public void messageDeleted(Message m, DTNHost where, boolean dropped) { - if (!dropped) { - processEvent(msgRemoveCheck, "Message removed", where, null, m); - } - else { - processEvent(msgDropCheck, "Message dropped", where, null, m); - } - } - - public void messageTransferred(Message m, DTNHost from, DTNHost to, - boolean firstDelivery) { - if (firstDelivery) { - processEvent(msgDeliveredCheck, "Message delivered", from, to, m); - } - else if (to == m.getTo()) { - processEvent(msgDeliveredCheck, "Message delivered again", - from, to, m); - } - else { - processEvent(msgRelayCheck, "Message relayed", from, to, m); - } - } - - public void newMessage(Message m) { - processEvent(msgCreateCheck, "Message created", m.getFrom(), null, m); - } - - public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { - processEvent(msgAbortCheck, "Message relay aborted", from, to, m); - } - - public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { - processEvent(msgTransferStartCheck,"Message relay started", from, - to,m); - - } - - // end of message interface implementations - - - /** - * Action listener for log entry (host & message) buttons - */ - public void actionPerformed(ActionEvent e) { - JButton source = (JButton)e.getSource(); - - if (source.getClientProperty(HOST_PROP) != null) { - // button was a host button -> focus it on GUI - gui.setFocus((DTNHost)source.getClientProperty(HOST_PROP)); - } - else if (source.getClientProperty(MSG_PROP) != null) { - // was a message button -> show information about the message - Message m = (Message)source.getClientProperty(MSG_PROP); - gui.getInfoPanel().showInfo(m); - } - } - - public String toString() { - return this.getClass().getSimpleName() + " with " + - this.eventPanes.size() + " events"; - } - -} + + eventPanes.add(eventPane); + + // if the log is full, remove oldest entries first + if (this.eventPanes.size() > maxNrofEvents) { + eventPanes.remove(0); + } + } + + /** + * Updates the log view + */ + private void updateLogView() { + //TODO Optimization: Check if update is really necessary + this.removeAll(); + for (int i=0; i< this.eventPanes.size(); i++) { + this.add(eventPanes.get(i)); + } + revalidate(); + } + + + /** + * Adds a new button to a log entry panel and attaches a client + * property into it + * @param panel Panel where to add the button + * @param o Client property object to add + * @param clientProp Client property key to use for the object + */ + private void addInfoButton(JPanel panel, Object o, String clientProp) { + JButton hButton; + hButton = new JButton(o.toString()); + hButton.putClientProperty(clientProp, o); + hButton.addActionListener(this); + hButton.setFont(font); + hButton.setMargin(new Insets(0,0,0,0)); + hButton.setBackground(LOG_BUTTON_BG); + panel.add(hButton); + } + + /** + * Processes a log event + * @param check EventLogControls used to check if this entry type should + * be shown and/or paused upon + * @param name Text description of the event + * @param host1 First host involved in the event (if any, can be null) + * @param host2 Second host involved in the event (if any, can be null) + * @param message The message involved in the event (if any, can be null) + */ + private void processEvent(EventLogControl check, final String name, + final DTNHost host1, final DTNHost host2, final Message message) { + String descString; // String format description of the event + + if (!check.showEvent()) { + return; // if event's "show" is not checked, won't pause either + } + + descString = name + " " + + (host1!=null ? host1 : "") + + (host2!= null ? (HOST_DELIM + host2) : "") + + (message!=null ? " " + message : ""); + + if (regExp != null && !descString.matches(regExp)){ + return; // description doesn't match defined regular expression + } + + if (check.pauseOnEvent()) { + gui.setPaused(true); + if (host1 != null) { + gui.setFocus(host1); + } + } + + addEvent(name, host1, host2, message, check.pauseOnEvent()); + } + + // Implementations of ConnectionListener and MessageListener interfaces + public void hostsConnected(DTNHost host1, DTNHost host2) { + processEvent(conUpCheck, "Connection UP", host1, host2, null); + } + + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + processEvent(conDownCheck, "Connection DOWN", host1, host2, null); + } + + public void messageDeleted(Message m, DTNHost where, boolean dropped) { + if (!dropped) { + processEvent(msgRemoveCheck, "Message removed", where, null, m); + } + else { + processEvent(msgDropCheck, "Message dropped", where, null, m); + } + } + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + if (firstDelivery) { + processEvent(msgDeliveredCheck, "Message delivered", from, to, m); + } + else if (to == m.getTo()) { + processEvent(msgDeliveredCheck, "Message delivered again", + from, to, m); + } + else { + processEvent(msgRelayCheck, "Message relayed", from, to, m); + } + } + + public void newMessage(Message m) { + processEvent(msgCreateCheck, "Message created", m.getFrom(), null, m); + } + + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { + processEvent(msgAbortCheck, "Message relay aborted", from, to, m); + } + + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { + processEvent(msgTransferStartCheck,"Message relay started", from, + to,m); + + } + + // end of message interface implementations + + + /** + * Action listener for log entry (host & message) buttons + */ + public void actionPerformed(ActionEvent e) { + JButton source = (JButton)e.getSource(); + + if (source.getClientProperty(HOST_PROP) != null) { + // button was a host button -> focus it on GUI + gui.setFocus((DTNHost)source.getClientProperty(HOST_PROP)); + } + else if (source.getClientProperty(MSG_PROP) != null) { + // was a message button -> show information about the message + Message m = (Message)source.getClientProperty(MSG_PROP); + gui.getInfoPanel().showInfo(m); + } + } + + public String toString() { + return this.getClass().getSimpleName() + " with " + + this.eventPanes.size() + " events"; + } + +} diff --git a/gui/GUIControls.java b/gui/GUIControls.java index d10dccad9..27fb470a9 100644 --- a/gui/GUIControls.java +++ b/gui/GUIControls.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui; - +package gui; + import gui.playfield.PlayField; import java.awt.FlowLayout; @@ -30,266 +30,266 @@ import core.Coord; import core.SimClock; - -/** - * GUI's control panel - * - */ -public class GUIControls extends JPanel implements ActionListener, ChangeListener { - private static final String PATH_GRAPHICS = "buttonGraphics/"; - private static final String ICON_PAUSE = "Pause16.gif"; - private static final String ICON_PLAY = "Play16.gif"; - private static final String ICON_ZOOM = "Zoom24.gif"; - private static final String ICON_STEP = "StepForward16.gif"; - private static final String ICON_FFW = "FastForward16.gif"; - - private static final String TEXT_PAUSE = "pause simulation"; - private static final String TEXT_PLAY = "play simulation"; - private static final String TEXT_PLAY_UNTIL = "play simulation until sim time..."; - private static final String TEXT_STEP = "step forward one interval"; - private static final String TEXT_FFW = "enable/disable fast forward"; - private static final String TEXT_UP_CHOOSER = "GUI update:"; - private static final String TEXT_SCREEN_SHOT = "screen shot"; - private static final String TEXT_SIMTIME = "Simulation time - "+ - "click to force update, right click to change format"; - private static final String TEXT_SEPS = "simulated seconds per second"; - - // "simulated events per second" averaging time (milliseconds) - private static final int EPS_AVG_TIME = 2000; - private static final String SCREENSHOT_FILE_TYPE = "png"; - private static final String SCREENSHOT_FILE = "screenshot"; - - private JTextField simTimeField; - private JLabel sepsField; // simulated events per second field - private JButton playButton; - private JButton playUntilButton; - private boolean paused; - private JButton stepButton; - private boolean step; - private JButton ffwButton; - private boolean isFfw; - private int oldSpeedIndex; // what speed was selected before FFW - - private JButton screenShotButton; - private JComboBox guiUpdateChooser; - - /** - * GUI update speeds. Negative values -> how many 1/10 seconds to wait - * between updates. Positive values -> show every Nth update - */ - public static final String[] UP_SPEEDS = {"-10", "-1", "0.1", "1", "10", - "100", "1000", "10000", "100000"}; - + +/** + * GUI's control panel + * + */ +public class GUIControls extends JPanel implements ActionListener, ChangeListener { + private static final String PATH_GRAPHICS = "buttonGraphics/"; + private static final String ICON_PAUSE = "Pause16.gif"; + private static final String ICON_PLAY = "Play16.gif"; + private static final String ICON_ZOOM = "Zoom24.gif"; + private static final String ICON_STEP = "StepForward16.gif"; + private static final String ICON_FFW = "FastForward16.gif"; + + private static final String TEXT_PAUSE = "pause simulation"; + private static final String TEXT_PLAY = "play simulation"; + private static final String TEXT_PLAY_UNTIL = "play simulation until sim time..."; + private static final String TEXT_STEP = "step forward one interval"; + private static final String TEXT_FFW = "enable/disable fast forward"; + private static final String TEXT_UP_CHOOSER = "GUI update:"; + private static final String TEXT_SCREEN_SHOT = "screen shot"; + private static final String TEXT_SIMTIME = "Simulation time - "+ + "click to force update, right click to change format"; + private static final String TEXT_SEPS = "simulated seconds per second"; + + // "simulated events per second" averaging time (milliseconds) + private static final int EPS_AVG_TIME = 2000; + private static final String SCREENSHOT_FILE_TYPE = "png"; + private static final String SCREENSHOT_FILE = "screenshot"; + + private JTextField simTimeField; + private JLabel sepsField; // simulated events per second field + private JButton playButton; + private JButton playUntilButton; + private boolean paused; + private JButton stepButton; + private boolean step; + private JButton ffwButton; + private boolean isFfw; + private int oldSpeedIndex; // what speed was selected before FFW + + private JButton screenShotButton; + private JComboBox guiUpdateChooser; + + /** + * GUI update speeds. Negative values -> how many 1/10 seconds to wait + * between updates. Positive values -> show every Nth update + */ + public static final String[] UP_SPEEDS = {"-10", "-1", "0.1", "1", "10", + "100", "1000", "10000", "100000"}; + /** Smallest value for the zoom level */ public static final double ZOOM_MIN = 0.001; /** Highest value for the zoom level */ public static final double ZOOM_MAX = 10; - - /** index of initial update speed setting */ - public static final int INITIAL_SPEED_SELECTION = 3; - /** index of FFW speed setting */ - public static final int FFW_SPEED_INDEX = 7; - - private double guiUpdateInterval; - private javax.swing.JSpinner zoomSelector; - - private PlayField pf; - private DTNSimGUI gui; - - private long lastUpdate; - private double lastSimTime; - private double playUntilTime; - + + /** index of initial update speed setting */ + public static final int INITIAL_SPEED_SELECTION = 3; + /** index of FFW speed setting */ + public static final int FFW_SPEED_INDEX = 7; + + private double guiUpdateInterval; + private javax.swing.JSpinner zoomSelector; + + private PlayField pf; + private DTNSimGUI gui; + + private long lastUpdate; + private double lastSimTime; + private double playUntilTime; + private boolean useHourDisplay = false; - + public GUIControls(DTNSimGUI gui, PlayField pf) { - /* TODO: read values for paused, isFfw etc from a file */ - this.pf = pf; - this.gui = gui; - this.lastUpdate = System.currentTimeMillis(); - this.lastSimTime = 0; - this.paused = true; - this.isFfw = false; - this.playUntilTime = Double.MAX_VALUE; - initPanel(); - } - - /** - * Creates panel's components and initializes them - */ - private void initPanel() { - this.setLayout(new FlowLayout()); - this.simTimeField = new JTextField("0.0"); - this.simTimeField.setColumns(6); - this.simTimeField.setEditable(false); - this.simTimeField.setToolTipText(TEXT_SIMTIME); - this.simTimeField.addMouseListener(new MouseAdapter(){ + /* TODO: read values for paused, isFfw etc from a file */ + this.pf = pf; + this.gui = gui; + this.lastUpdate = System.currentTimeMillis(); + this.lastSimTime = 0; + this.paused = true; + this.isFfw = false; + this.playUntilTime = Double.MAX_VALUE; + initPanel(); + } + + /** + * Creates panel's components and initializes them + */ + private void initPanel() { + this.setLayout(new FlowLayout()); + this.simTimeField = new JTextField("0.0"); + this.simTimeField.setColumns(6); + this.simTimeField.setEditable(false); + this.simTimeField.setToolTipText(TEXT_SIMTIME); + this.simTimeField.addMouseListener(new MouseAdapter(){ public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { + if (e.getButton() == MouseEvent.BUTTON3) { useHourDisplay = !useHourDisplay; - } - setSimTime(SimClock.getTime()); - } - }); - - this.sepsField = new JLabel("0.00"); - this.sepsField.setToolTipText(TEXT_SEPS); - - this.screenShotButton = new JButton(TEXT_SCREEN_SHOT); - this.guiUpdateChooser = new JComboBox(UP_SPEEDS); - - this.zoomSelector = new JSpinner(new SpinnerNumberModel(1.0, ZOOM_MIN, - ZOOM_MAX, 0.001)); - - this.add(simTimeField); + } + setSimTime(SimClock.getTime()); + } + }); + + this.sepsField = new JLabel("0.00"); + this.sepsField.setToolTipText(TEXT_SEPS); + + this.screenShotButton = new JButton(TEXT_SCREEN_SHOT); + this.guiUpdateChooser = new JComboBox(UP_SPEEDS); + + this.zoomSelector = new JSpinner(new SpinnerNumberModel(1.0, ZOOM_MIN, + ZOOM_MAX, 0.001)); + + this.add(simTimeField); this.add(sepsField); - - playButton = addButton(paused ? ICON_PLAY : ICON_PAUSE, - paused ? TEXT_PLAY : TEXT_PAUSE); - stepButton = addButton(ICON_STEP, TEXT_STEP); - ffwButton = addButton(ICON_FFW, TEXT_FFW); - playUntilButton = addButton(ICON_PLAY, TEXT_PLAY_UNTIL); - playUntilButton.setText("..."); - - this.add(new JLabel(TEXT_UP_CHOOSER)); - this.add(this.guiUpdateChooser); - this.guiUpdateChooser.setSelectedIndex(INITIAL_SPEED_SELECTION); - this.updateUpdateInterval(); - - this.add(new JLabel(createImageIcon(ICON_ZOOM))); - this.updateZoomScale(false); - - this.add(this.zoomSelector); - this.add(this.screenShotButton); - - guiUpdateChooser.addActionListener(this); - zoomSelector.addChangeListener(this); - this.screenShotButton.addActionListener(this); - } - - - private ImageIcon createImageIcon(String path) { - java.net.URL imgURL = getClass().getResource(PATH_GRAPHICS+path); - return new ImageIcon(imgURL); - } - - - private JButton addButton(String iconPath, String tooltip) { - JButton button = new JButton(createImageIcon(iconPath)); - button.setToolTipText(tooltip); - button.addActionListener(this); - this.add(button); - return button; - } - - /** - * Sets the simulation time that control panel shows - * @param time The time to show - */ - public void setSimTime(double time) { - long timeSinceUpdate = System.currentTimeMillis() - this.lastUpdate; - - if (timeSinceUpdate > EPS_AVG_TIME) { - double val = ((time - this.lastSimTime) * 1000)/timeSinceUpdate; - String sepsValue = String.format("%.2f 1/s", val); - - this.sepsField.setText(sepsValue); - this.lastSimTime = time; - this.lastUpdate = System.currentTimeMillis(); - } - + + playButton = addButton(paused ? ICON_PLAY : ICON_PAUSE, + paused ? TEXT_PLAY : TEXT_PAUSE); + stepButton = addButton(ICON_STEP, TEXT_STEP); + ffwButton = addButton(ICON_FFW, TEXT_FFW); + playUntilButton = addButton(ICON_PLAY, TEXT_PLAY_UNTIL); + playUntilButton.setText("..."); + + this.add(new JLabel(TEXT_UP_CHOOSER)); + this.add(this.guiUpdateChooser); + this.guiUpdateChooser.setSelectedIndex(INITIAL_SPEED_SELECTION); + this.updateUpdateInterval(); + + this.add(new JLabel(createImageIcon(ICON_ZOOM))); + this.updateZoomScale(false); + + this.add(this.zoomSelector); + this.add(this.screenShotButton); + + guiUpdateChooser.addActionListener(this); + zoomSelector.addChangeListener(this); + this.screenShotButton.addActionListener(this); + } + + + private ImageIcon createImageIcon(String path) { + java.net.URL imgURL = getClass().getResource(PATH_GRAPHICS+path); + return new ImageIcon(imgURL); + } + + + private JButton addButton(String iconPath, String tooltip) { + JButton button = new JButton(createImageIcon(iconPath)); + button.setToolTipText(tooltip); + button.addActionListener(this); + this.add(button); + return button; + } + + /** + * Sets the simulation time that control panel shows + * @param time The time to show + */ + public void setSimTime(double time) { + long timeSinceUpdate = System.currentTimeMillis() - this.lastUpdate; + + if (timeSinceUpdate > EPS_AVG_TIME) { + double val = ((time - this.lastSimTime) * 1000)/timeSinceUpdate; + String sepsValue = String.format("%.2f 1/s", val); + + this.sepsField.setText(sepsValue); + this.lastSimTime = time; + this.lastUpdate = System.currentTimeMillis(); + } + if (this.useHourDisplay) { int hours = (int)(time / 3600); int mins = (int)((time - hours * 3600) / 60); double secs = time % 60; this.simTimeField.setText(String.format("%02d:%02d:%02.1f", hours, mins, secs)); - } else { + } else { this.simTimeField.setText(String.format("%.1f", time)); - } - } - - /** - * Sets simulation to pause or play. - * @param paused If true, simulation is put to pause - */ - public void setPaused(boolean paused) { - if (!paused) { - this.playButton.setIcon(createImageIcon(ICON_PAUSE)); - this.playButton.setToolTipText(TEXT_PAUSE); - this.paused = false; - if (SimClock.getTime() >= this.playUntilTime) { - // playUntilTime passed -> disable it - this.playUntilTime = Double.MAX_VALUE; - } - } - else { - this.playButton.setIcon(createImageIcon(ICON_PLAY)); - this.playButton.setToolTipText(TEXT_PLAY); - this.paused = true; - this.setSimTime(SimClock.getTime()); - this.pf.updateField(); - } - } - - private void switchFfw() { - if (isFfw) { - this.isFfw = false; // set to normal play - this.ffwButton.setIcon(createImageIcon(ICON_FFW)); - this.guiUpdateChooser.setSelectedIndex(oldSpeedIndex); - this.ffwButton.setSelected(false); - } - else { - this.oldSpeedIndex = this.guiUpdateChooser.getSelectedIndex(); - this.guiUpdateChooser.setSelectedIndex(FFW_SPEED_INDEX); - this.isFfw = true; // set to FFW - this.ffwButton.setIcon(createImageIcon(ICON_PLAY)); - } - } - - /** - * Has user requested the simulation to be paused - * @return True if pause is requested - */ - public boolean isPaused() { - if (step) { // if we want to step, return false once and reset stepping - step = false; - return false; - } - if (SimClock.getTime() >= this.playUntilTime) { - this.setPaused(true); - } - return this.paused; - } - - /** - * Is fast forward turned on - * @return True if FFW is on, false if not - */ - public boolean isFfw() { - return this.isFfw; - } - - /** - * Returns the selected update interval of GUI - * @return The update interval (seconds) - */ - public double getUpdateInterval() { - return this.guiUpdateInterval; - } - - /** - * Changes the zoom level - * @param delta How much to change the current level (can be negative or - * positive) - */ - public void changeZoom(int delta) { - SpinnerNumberModel model = + } + } + + /** + * Sets simulation to pause or play. + * @param paused If true, simulation is put to pause + */ + public void setPaused(boolean paused) { + if (!paused) { + this.playButton.setIcon(createImageIcon(ICON_PAUSE)); + this.playButton.setToolTipText(TEXT_PAUSE); + this.paused = false; + if (SimClock.getTime() >= this.playUntilTime) { + // playUntilTime passed -> disable it + this.playUntilTime = Double.MAX_VALUE; + } + } + else { + this.playButton.setIcon(createImageIcon(ICON_PLAY)); + this.playButton.setToolTipText(TEXT_PLAY); + this.paused = true; + this.setSimTime(SimClock.getTime()); + this.pf.updateField(); + } + } + + private void switchFfw() { + if (isFfw) { + this.isFfw = false; // set to normal play + this.ffwButton.setIcon(createImageIcon(ICON_FFW)); + this.guiUpdateChooser.setSelectedIndex(oldSpeedIndex); + this.ffwButton.setSelected(false); + } + else { + this.oldSpeedIndex = this.guiUpdateChooser.getSelectedIndex(); + this.guiUpdateChooser.setSelectedIndex(FFW_SPEED_INDEX); + this.isFfw = true; // set to FFW + this.ffwButton.setIcon(createImageIcon(ICON_PLAY)); + } + } + + /** + * Has user requested the simulation to be paused + * @return True if pause is requested + */ + public boolean isPaused() { + if (step) { // if we want to step, return false once and reset stepping + step = false; + return false; + } + if (SimClock.getTime() >= this.playUntilTime) { + this.setPaused(true); + } + return this.paused; + } + + /** + * Is fast forward turned on + * @return True if FFW is on, false if not + */ + public boolean isFfw() { + return this.isFfw; + } + + /** + * Returns the selected update interval of GUI + * @return The update interval (seconds) + */ + public double getUpdateInterval() { + return this.guiUpdateInterval; + } + + /** + * Changes the zoom level + * @param delta How much to change the current level (can be negative or + * positive) + */ + public void changeZoom(int delta) { + SpinnerNumberModel model = (SpinnerNumberModel)this.zoomSelector.getModel(); double curZoom = model.getNumber().doubleValue(); Number newValue = new Double(curZoom + model.getStepSize(). - doubleValue() * delta * curZoom * 100); - + doubleValue() * delta * curZoom * 100); + if (newValue.doubleValue() < ZOOM_MIN) { newValue = ZOOM_MIN; } else if (newValue.doubleValue() > ZOOM_MAX) { @@ -297,100 +297,100 @@ public void changeZoom(int delta) { } model.setValue(newValue); - this.updateZoomScale(true); - } - - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == this.playButton) { - setPaused(!this.paused); // switch pause/play - } - else if (e.getSource() == this.stepButton) { - setPaused(true); - this.step = true; - } - else if (e.getSource() == this.ffwButton) { - switchFfw(); - } - else if (e.getSource() == this.playUntilButton) { - setPlayUntil(); - } - else if (e.getSource() == this.guiUpdateChooser) { - updateUpdateInterval(); - } - else if (e.getSource() == this.screenShotButton) { - takeScreenShot(); - } + this.updateZoomScale(true); + } + + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == this.playButton) { + setPaused(!this.paused); // switch pause/play + } + else if (e.getSource() == this.stepButton) { + setPaused(true); + this.step = true; + } + else if (e.getSource() == this.ffwButton) { + switchFfw(); + } + else if (e.getSource() == this.playUntilButton) { + setPlayUntil(); + } + else if (e.getSource() == this.guiUpdateChooser) { + updateUpdateInterval(); + } + else if (e.getSource() == this.screenShotButton) { + takeScreenShot(); + } } - - + + public void stateChanged(ChangeEvent e) { updateZoomScale(true); - } - - - private void setPlayUntil() { - setPaused(true); - String value = JOptionPane.showInputDialog(TEXT_PLAY_UNTIL); - if (value == null) { - return; - } - try { - this.playUntilTime = Double.parseDouble(value); - setPaused(false); - } catch (NumberFormatException e) { - JOptionPane.showMessageDialog(gui.getParentFrame(), - "Invalid number '" + value+"'", - "error",JOptionPane.ERROR_MESSAGE); - } - } - - - private void updateUpdateInterval() { - String selString = (String)this.guiUpdateChooser.getSelectedItem(); - this.guiUpdateInterval = Double.parseDouble(selString); - } - - /** - * Updates zoom scale to the one selected by zoom chooser - * @param centerView If true, the center of the viewport should remain - * the same - */ - private void updateZoomScale(boolean centerView) { + } + + + private void setPlayUntil() { + setPaused(true); + String value = JOptionPane.showInputDialog(TEXT_PLAY_UNTIL); + if (value == null) { + return; + } + try { + this.playUntilTime = Double.parseDouble(value); + setPaused(false); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(gui.getParentFrame(), + "Invalid number '" + value+"'", + "error",JOptionPane.ERROR_MESSAGE); + } + } + + + private void updateUpdateInterval() { + String selString = (String)this.guiUpdateChooser.getSelectedItem(); + this.guiUpdateInterval = Double.parseDouble(selString); + } + + /** + * Updates zoom scale to the one selected by zoom chooser + * @param centerView If true, the center of the viewport should remain + * the same + */ + private void updateZoomScale(boolean centerView) { double scale = ((SpinnerNumberModel)zoomSelector.getModel()). - getNumber().doubleValue(); - - if (centerView) { - Coord center = gui.getCenterViewCoord(); - this.pf.setScale(scale); - gui.centerViewAt(center); - } - else { - this.pf.setScale(scale); - } - } - - private void takeScreenShot() { - try { - JFileChooser fc = new JFileChooser(); - fc.setSelectedFile(new File(SCREENSHOT_FILE + - "." + SCREENSHOT_FILE_TYPE)); - int retVal = fc.showSaveDialog(this); - if (retVal == JFileChooser.APPROVE_OPTION) { - File file = fc.getSelectedFile(); - BufferedImage i = new BufferedImage(this.pf.getWidth(), - this.pf.getHeight(), BufferedImage.TYPE_INT_RGB); - Graphics2D g2 = i.createGraphics(); - - this.pf.paint(g2); // paint playfield to buffered image - ImageIO.write(i, SCREENSHOT_FILE_TYPE, file); - } - } - catch (Exception e) { - JOptionPane.showMessageDialog(gui.getParentFrame(), - "screenshot failed (problems with output file?)", - "Exception", JOptionPane.ERROR_MESSAGE); - } - } - -} + getNumber().doubleValue(); + + if (centerView) { + Coord center = gui.getCenterViewCoord(); + this.pf.setScale(scale); + gui.centerViewAt(center); + } + else { + this.pf.setScale(scale); + } + } + + private void takeScreenShot() { + try { + JFileChooser fc = new JFileChooser(); + fc.setSelectedFile(new File(SCREENSHOT_FILE + + "." + SCREENSHOT_FILE_TYPE)); + int retVal = fc.showSaveDialog(this); + if (retVal == JFileChooser.APPROVE_OPTION) { + File file = fc.getSelectedFile(); + BufferedImage i = new BufferedImage(this.pf.getWidth(), + this.pf.getHeight(), BufferedImage.TYPE_INT_RGB); + Graphics2D g2 = i.createGraphics(); + + this.pf.paint(g2); // paint playfield to buffered image + ImageIO.write(i, SCREENSHOT_FILE_TYPE, file); + } + } + catch (Exception e) { + JOptionPane.showMessageDialog(gui.getParentFrame(), + "screenshot failed (problems with output file?)", + "Exception", JOptionPane.ERROR_MESSAGE); + } + } + +} diff --git a/gui/InfoPanel.java b/gui/InfoPanel.java index c34c7a8d7..e262ba1f3 100644 --- a/gui/InfoPanel.java +++ b/gui/InfoPanel.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui; - +package gui; + import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collections; @@ -17,118 +17,118 @@ import movement.Path; import core.DTNHost; import core.Message; - -/** - * Information panel that shows data of selected messages and nodes. - */ -public class InfoPanel extends JPanel implements ActionListener{ - private JComboBox msgChooser; - private JLabel info; - private JButton infoButton; - private JButton routingInfoButton; - private Message selectedMessage; - private DTNHost selectedHost; - private DTNSimGUI gui; - - public InfoPanel(DTNSimGUI gui) { - this.gui = gui; - reset(); - } - - private void reset() { - this.removeAll(); - this.repaint(); - this.info = null; - this.infoButton = null; - this.selectedMessage = null; - } - - /** - * Show information about a host - * @param host Host to show the information of - */ - public void showInfo(DTNHost host) { - Vector messages = - new Vector(host.getMessageCollection()); - Collections.sort(messages); - reset(); - this.selectedHost = host; - String text = (host.isMovementActive() ? "" : "INACTIVE ") + host + - " at " + host.getLocation(); - - msgChooser = new JComboBox(messages); - msgChooser.insertItemAt(messages.size() + " messages", 0); - msgChooser.setSelectedIndex(0); - msgChooser.addActionListener(this); - - routingInfoButton = new JButton("routing info"); - routingInfoButton.addActionListener(this); - - this.add(new JLabel(text)); - this.add(msgChooser); - this.add(routingInfoButton); - this.revalidate(); - } - - /** - * Show information about a message - * @param message Message to show the information of - */ - public void showInfo(Message message) { - reset(); - this.add(new JLabel(message.toString())); - setMessageInfo(message); - this.revalidate(); - } - - private void setMessageInfo(Message m) { - int ttl = m.getTtl(); - String txt = " [" + m.getFrom() + "->" + m.getTo() + "] " + - "size:" + m.getSize() + ", UI:" + m.getUniqueId() + - ", received @ " + String.format("%.2f", m.getReceiveTime()); - if (ttl != Integer.MAX_VALUE) { - txt += " TTL: " + ttl; - } - - String butTxt = "path: " + (m.getHops().size()-1) + " hops"; - - if (this.info == null) { - this.info = new JLabel(txt); - this.infoButton = new JButton(butTxt); - this.add(info); - this.add(infoButton); - infoButton.addActionListener(this); - } - else { - this.info.setText(txt); - this.infoButton.setText(butTxt); - } - - this.selectedMessage = m; - infoButton.setToolTipText("path:" + m.getHops()); - - this.revalidate(); - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == msgChooser) { - if (msgChooser.getSelectedIndex() == 0) { // title text selected - return; - } - Message m = (Message)msgChooser.getSelectedItem(); - setMessageInfo(m); - } - else if (e.getSource() == this.infoButton) { - Path p = new Path(); - for (DTNHost h : this.selectedMessage.getHops()) { - p.addWaypoint(h.getLocation()); - } - - this.gui.showPath(p); - } - else if (e.getSource() == this.routingInfoButton) { - new RoutingInfoWindow(this.selectedHost); - } - } - -} \ No newline at end of file + +/** + * Information panel that shows data of selected messages and nodes. + */ +public class InfoPanel extends JPanel implements ActionListener{ + private JComboBox msgChooser; + private JLabel info; + private JButton infoButton; + private JButton routingInfoButton; + private Message selectedMessage; + private DTNHost selectedHost; + private DTNSimGUI gui; + + public InfoPanel(DTNSimGUI gui) { + this.gui = gui; + reset(); + } + + private void reset() { + this.removeAll(); + this.repaint(); + this.info = null; + this.infoButton = null; + this.selectedMessage = null; + } + + /** + * Show information about a host + * @param host Host to show the information of + */ + public void showInfo(DTNHost host) { + Vector messages = + new Vector(host.getMessageCollection()); + Collections.sort(messages); + reset(); + this.selectedHost = host; + String text = (host.isMovementActive() ? "" : "INACTIVE ") + host + + " at " + host.getLocation(); + + msgChooser = new JComboBox(messages); + msgChooser.insertItemAt(messages.size() + " messages", 0); + msgChooser.setSelectedIndex(0); + msgChooser.addActionListener(this); + + routingInfoButton = new JButton("routing info"); + routingInfoButton.addActionListener(this); + + this.add(new JLabel(text)); + this.add(msgChooser); + this.add(routingInfoButton); + this.revalidate(); + } + + /** + * Show information about a message + * @param message Message to show the information of + */ + public void showInfo(Message message) { + reset(); + this.add(new JLabel(message.toString())); + setMessageInfo(message); + this.revalidate(); + } + + private void setMessageInfo(Message m) { + int ttl = m.getTtl(); + String txt = " [" + m.getFrom() + "->" + m.getTo() + "] " + + "size:" + m.getSize() + ", UI:" + m.getUniqueId() + + ", received @ " + String.format("%.2f", m.getReceiveTime()); + if (ttl != Integer.MAX_VALUE) { + txt += " TTL: " + ttl; + } + + String butTxt = "path: " + (m.getHops().size()-1) + " hops"; + + if (this.info == null) { + this.info = new JLabel(txt); + this.infoButton = new JButton(butTxt); + this.add(info); + this.add(infoButton); + infoButton.addActionListener(this); + } + else { + this.info.setText(txt); + this.infoButton.setText(butTxt); + } + + this.selectedMessage = m; + infoButton.setToolTipText("path:" + m.getHops()); + + this.revalidate(); + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == msgChooser) { + if (msgChooser.getSelectedIndex() == 0) { // title text selected + return; + } + Message m = (Message)msgChooser.getSelectedItem(); + setMessageInfo(m); + } + else if (e.getSource() == this.infoButton) { + Path p = new Path(); + for (DTNHost h : this.selectedMessage.getHops()) { + p.addWaypoint(h.getLocation()); + } + + this.gui.showPath(p); + } + else if (e.getSource() == this.routingInfoButton) { + new RoutingInfoWindow(this.selectedHost); + } + } + +} diff --git a/gui/MainWindow.java b/gui/MainWindow.java index 6e55fea10..d03cd9f53 100644 --- a/gui/MainWindow.java +++ b/gui/MainWindow.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui; - +package gui; + import gui.playfield.PlayField; import java.awt.BorderLayout; @@ -17,96 +17,96 @@ import core.Settings; import core.World; - -/** - * Main window for the program. Takes care of layouting the main components - * in the window. - */ + +/** + * Main window for the program. Takes care of layouting the main components + * in the window. + */ public class MainWindow extends JFrame { /** The namespace for general GUI settings */ public static final String GUI_NS = "GUI"; - + /** Main window settings namespace ({@value}) */ public static final String GUI_WIN_NS = GUI_NS + ".window"; - - /** Window width -setting id ({@value}). Defines the width of the GUI + + /** Window width -setting id ({@value}). Defines the width of the GUI * window. Default {@link #WIN_DEFAULT_WIDTH} */ public static final String WIN_WIDTH_S = "width"; - /** Window height -setting id ({@value}). Defines the height of the GUI + /** Window height -setting id ({@value}). Defines the height of the GUI * window. Default {@link #WIN_DEFAULT_HEIGHT} */ public static final String WIN_HEIGHT_S = "height"; - + /** Default width for the GUI window */ - public static final int WIN_DEFAULT_WIDTH = 900; + public static final int WIN_DEFAULT_WIDTH = 900; /** Default height for the GUI window */ - public static final int WIN_DEFAULT_HEIGHT = 700; - - public static final String WINDOW_TITLE = "ONE"; - /** log panel's initial weight in the split panel */ - private static final double SPLIT_PANE_LOG_WEIGHT = 0.2; - - private JScrollPane playFieldScroll; - - public MainWindow(String scenName, World world, PlayField field, - GUIControls guiControls, InfoPanel infoPanel, - EventLogPanel elp, DTNSimGUI gui) { - super(WINDOW_TITLE + " - " + scenName); - JFrame.setDefaultLookAndFeelDecorated(true); - setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - - JPanel leftPane = new JPanel(); - leftPane.setLayout(new BoxLayout(leftPane,BoxLayout.Y_AXIS)); - JScrollPane hostListScroll; - JSplitPane fieldLogSplit; - JSplitPane logControlSplit; - JSplitPane mainSplit; + public static final int WIN_DEFAULT_HEIGHT = 700; + + public static final String WINDOW_TITLE = "ONE"; + /** log panel's initial weight in the split panel */ + private static final double SPLIT_PANE_LOG_WEIGHT = 0.2; + + private JScrollPane playFieldScroll; + + public MainWindow(String scenName, World world, PlayField field, + GUIControls guiControls, InfoPanel infoPanel, + EventLogPanel elp, DTNSimGUI gui) { + super(WINDOW_TITLE + " - " + scenName); + JFrame.setDefaultLookAndFeelDecorated(true); + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + + JPanel leftPane = new JPanel(); + leftPane.setLayout(new BoxLayout(leftPane,BoxLayout.Y_AXIS)); + JScrollPane hostListScroll; + JSplitPane fieldLogSplit; + JSplitPane logControlSplit; + JSplitPane mainSplit; Settings s = new Settings(GUI_WIN_NS); NodeChooser chooser = new NodeChooser(world.getHosts(),gui); - - setLayout(new BorderLayout()); - setJMenuBar(new SimMenuBar(field, chooser)); - + + setLayout(new BorderLayout()); + setJMenuBar(new SimMenuBar(field, chooser)); + playFieldScroll = new JScrollPane(field); - playFieldScroll.setMaximumSize(new Dimension(Integer.MAX_VALUE, - Integer.MAX_VALUE)); - - hostListScroll = new JScrollPane(chooser); - hostListScroll.setHorizontalScrollBarPolicy( - JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - - logControlSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, - new JScrollPane(elp.getControls()),new JScrollPane(elp)); - logControlSplit.setResizeWeight(0.1); - logControlSplit.setOneTouchExpandable(true); - - fieldLogSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, - leftPane, logControlSplit); - fieldLogSplit.setResizeWeight(1-SPLIT_PANE_LOG_WEIGHT); - fieldLogSplit.setOneTouchExpandable(true); - + playFieldScroll.setMaximumSize(new Dimension(Integer.MAX_VALUE, + Integer.MAX_VALUE)); + + hostListScroll = new JScrollPane(chooser); + hostListScroll.setHorizontalScrollBarPolicy( + JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + logControlSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + new JScrollPane(elp.getControls()),new JScrollPane(elp)); + logControlSplit.setResizeWeight(0.1); + logControlSplit.setOneTouchExpandable(true); + + fieldLogSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, + leftPane, logControlSplit); + fieldLogSplit.setResizeWeight(1-SPLIT_PANE_LOG_WEIGHT); + fieldLogSplit.setOneTouchExpandable(true); + setPreferredSize(new Dimension( - s.getInt(WIN_WIDTH_S, WIN_DEFAULT_WIDTH), - s.getInt(WIN_HEIGHT_S, WIN_DEFAULT_HEIGHT))); - - leftPane.add(guiControls); - leftPane.add(playFieldScroll); - leftPane.add(infoPanel); - - mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, - fieldLogSplit, hostListScroll); - mainSplit.setOneTouchExpandable(true); - mainSplit.setResizeWeight(0.8); - this.getContentPane().add(mainSplit); - - pack(); - } - - /** - * Returns a reference of the play field scroll panel - * @return a reference of the play field scroll panel - */ - public JScrollPane getPlayFieldScroll() { - return this.playFieldScroll; - } - -} + s.getInt(WIN_WIDTH_S, WIN_DEFAULT_WIDTH), + s.getInt(WIN_HEIGHT_S, WIN_DEFAULT_HEIGHT))); + + leftPane.add(guiControls); + leftPane.add(playFieldScroll); + leftPane.add(infoPanel); + + mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + fieldLogSplit, hostListScroll); + mainSplit.setOneTouchExpandable(true); + mainSplit.setResizeWeight(0.8); + this.getContentPane().add(mainSplit); + + pack(); + } + + /** + * Returns a reference of the play field scroll panel + * @return a reference of the play field scroll panel + */ + public JScrollPane getPlayFieldScroll() { + return this.playFieldScroll; + } + +} diff --git a/gui/NodeChooser.java b/gui/NodeChooser.java index 7e8afdb0d..65457b268 100644 --- a/gui/NodeChooser.java +++ b/gui/NodeChooser.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui; - +package gui; + import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; @@ -24,40 +24,40 @@ import gui.playfield.NodeGraphic; import core.DTNHost; import core.Settings; - -/** - * Node chooser panel - */ -public class NodeChooser extends JPanel implements ActionListener { - private DTNSimGUI gui; - /** the maximum number of allNodes to show in the list per page */ + +/** + * Node chooser panel + */ +public class NodeChooser extends JPanel implements ActionListener { + private DTNSimGUI gui; + /** the maximum number of allNodes to show in the list per page */ public static final int MAX_NODE_COUNT = 500; private Timer refreshTimer; /** how often auto refresh is performed */ private static final int AUTO_REFRESH_DELAY = 100; - + /** Default message node filters -setting id ({@value}). Comma separate * list of message IDs from which the default filter set is created. */ public static final String NODE_MESSAGE_FILTERS_S = "nodeMessageFilters"; - - private static final String HOST_KEY = "host"; + + private static final String HOST_KEY = "host"; private List allNodes; private List shownNodes; - - private JComboBox groupChooser; - private JPanel nodesPanel; + + private JComboBox groupChooser; + private JPanel nodesPanel; private JPanel chooserPanel; - private Vector filters; + private Vector filters; + - public NodeChooser(List nodes, DTNSimGUI gui) { - Settings s = new Settings(MainWindow.GUI_NS); + Settings s = new Settings(MainWindow.GUI_NS); // create a replicate to not interfere with original's ordering - this.allNodes = new ArrayList(nodes); - this.shownNodes = allNodes; + this.allNodes = new ArrayList(nodes); + this.shownNodes = allNodes; this.gui = gui; this.filters = new Vector(); - + if (s.contains(NODE_MESSAGE_FILTERS_S)) { String[] filterIds = s.getCsvSetting(NODE_MESSAGE_FILTERS_S); for (String id : filterIds) { @@ -66,12 +66,12 @@ public NodeChooser(List nodes, DTNSimGUI gui) { this.refreshTimer.start(); } } - - Collections.sort(this.allNodes); - - init(); + + Collections.sort(this.allNodes); + + init(); } - + /** * Adds a new node filter to the node chooser * @param f The filter to add @@ -84,7 +84,7 @@ public void addFilter(NodeFilter f) { this.refreshTimer.start(); } } - + /** * Clears all node filters */ @@ -95,24 +95,24 @@ public void clearFilters() { this.refreshTimer.stop(); } this.refreshTimer = null; - + NodeGraphic.setHighlightedNodes(null); updateList(); } - + private void updateList() { setNodes(0); if (this.groupChooser != null) { this.groupChooser.setSelectedIndex(0); } } - - + + private void updateShownNodes() { List oldShownNodes = shownNodes; Listnodes = new Vector(); - - for (DTNHost node : allNodes) { + + for (DTNHost node : allNodes) { for (NodeFilter f : this.filters) { if (f.filterNode(node)) { nodes.add(node); @@ -120,7 +120,7 @@ private void updateShownNodes() { } } } - + if (nodes.size() == oldShownNodes.size() && oldShownNodes.containsAll(nodes)) { return; /* nothing to update */ @@ -129,84 +129,84 @@ private void updateShownNodes() { updateList(); NodeGraphic.setHighlightedNodes(nodes); } - - } - - /** - * Initializes the node chooser panels - */ - private void init() { - nodesPanel = new JPanel(); - chooserPanel = new JPanel(); - - this.setLayout(new GridBagLayout()); - GridBagConstraints c = new GridBagConstraints(); - c.anchor = GridBagConstraints.FIRST_LINE_START; - - nodesPanel.setLayout(new BoxLayout(nodesPanel,BoxLayout.Y_AXIS)); - nodesPanel.setBorder(BorderFactory.createTitledBorder(getBorder(), - "Nodes")); - - if (shownNodes.size() > MAX_NODE_COUNT) { + + } + + /** + * Initializes the node chooser panels + */ + private void init() { + nodesPanel = new JPanel(); + chooserPanel = new JPanel(); + + this.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.anchor = GridBagConstraints.FIRST_LINE_START; + + nodesPanel.setLayout(new BoxLayout(nodesPanel,BoxLayout.Y_AXIS)); + nodesPanel.setBorder(BorderFactory.createTitledBorder(getBorder(), + "Nodes")); + + if (shownNodes.size() > MAX_NODE_COUNT) { String[] groupNames = new String[(shownNodes.size()-1) - / MAX_NODE_COUNT+1]; - int last = 0; - for (int i=0, n=shownNodes.size(); - i <= (n-1) / MAX_NODE_COUNT; i++) { - int next = MAX_NODE_COUNT * (i+1) - 1; - if (next > n) { - next = n-1; - } - groupNames[i] = (last + "..." + next); - last = next + 1; - } - groupChooser = new JComboBox(groupNames); - groupChooser.addActionListener(this); - chooserPanel.add(groupChooser); - } - - setNodes(0); - c.gridy = 0; - this.add(chooserPanel, c); - c.gridy = 1; - this.add(nodesPanel, c); - } - - /** - * Sets the right set of allNodes to display - * @param offset Index of the first node to show - */ - private void setNodes(int offset) { - nodesPanel.removeAll(); - - for (int i=offset; i< shownNodes.size() && - i < offset + MAX_NODE_COUNT; i++) { - DTNHost h = shownNodes.get(i); - JButton jb = new JButton(h.toString()); - jb.putClientProperty(HOST_KEY, h); - jb.addActionListener(this); - nodesPanel.add(jb); - } - - revalidate(); - repaint(); - } - - /** - * Action listener method for buttons and node set chooser - */ - public void actionPerformed(ActionEvent e) { - if (e.getSource() instanceof JButton) { - JButton source = (JButton)e.getSource(); - DTNHost host = (DTNHost)source.getClientProperty(HOST_KEY); - gui.setFocus(host); - } - else if (e.getSource() == this.groupChooser) { - setNodes(groupChooser.getSelectedIndex() * MAX_NODE_COUNT); + / MAX_NODE_COUNT+1]; + int last = 0; + for (int i=0, n=shownNodes.size(); + i <= (n-1) / MAX_NODE_COUNT; i++) { + int next = MAX_NODE_COUNT * (i+1) - 1; + if (next > n) { + next = n-1; + } + groupNames[i] = (last + "..." + next); + last = next + 1; + } + groupChooser = new JComboBox(groupNames); + groupChooser.addActionListener(this); + chooserPanel.add(groupChooser); + } + + setNodes(0); + c.gridy = 0; + this.add(chooserPanel, c); + c.gridy = 1; + this.add(nodesPanel, c); + } + + /** + * Sets the right set of allNodes to display + * @param offset Index of the first node to show + */ + private void setNodes(int offset) { + nodesPanel.removeAll(); + + for (int i=offset; i< shownNodes.size() && + i < offset + MAX_NODE_COUNT; i++) { + DTNHost h = shownNodes.get(i); + JButton jb = new JButton(h.toString()); + jb.putClientProperty(HOST_KEY, h); + jb.addActionListener(this); + nodesPanel.add(jb); + } + + revalidate(); + repaint(); + } + + /** + * Action listener method for buttons and node set chooser + */ + public void actionPerformed(ActionEvent e) { + if (e.getSource() instanceof JButton) { + JButton source = (JButton)e.getSource(); + DTNHost host = (DTNHost)source.getClientProperty(HOST_KEY); + gui.setFocus(host); + } + else if (e.getSource() == this.groupChooser) { + setNodes(groupChooser.getSelectedIndex() * MAX_NODE_COUNT); } else if (e.getSource() == this.refreshTimer) { updateShownNodes(); - } - } - -} + } + } + +} diff --git a/gui/RoutingInfoWindow.java b/gui/RoutingInfoWindow.java index 74366ac9a..307b278a8 100644 --- a/gui/RoutingInfoWindow.java +++ b/gui/RoutingInfoWindow.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui; - +package gui; + import java.awt.BorderLayout; import java.awt.Container; import java.awt.event.ActionEvent; @@ -22,52 +22,52 @@ import routing.util.RoutingInfo; import core.DTNHost; import core.SimClock; - -/** - * A window for displaying routing information - */ -public class RoutingInfoWindow extends JFrame implements ActionListener { - private DTNHost host; + +/** + * A window for displaying routing information + */ +public class RoutingInfoWindow extends JFrame implements ActionListener { + private DTNHost host; private JButton refreshButton; - private JCheckBox autoRefresh; + private JCheckBox autoRefresh; private JScrollPane treePane; private JTree tree; - private Timer refreshTimer; + private Timer refreshTimer; /** how often auto refresh is performed */ private static final int AUTO_REFRESH_DELAY = 1000; - - public RoutingInfoWindow(DTNHost host) { - Container cp = this.getContentPane(); + + public RoutingInfoWindow(DTNHost host) { + Container cp = this.getContentPane(); JPanel refreshPanel = new JPanel(); - this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - this.host = host; + this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + this.host = host; this.setLayout(new BorderLayout()); - refreshPanel.setLayout(new BorderLayout()); + refreshPanel.setLayout(new BorderLayout()); this.autoRefresh = new JCheckBox("Auto refresh"); - this.autoRefresh.addActionListener(this); - this.treePane = new JScrollPane(); - updateTree(); - + this.autoRefresh.addActionListener(this); + this.treePane = new JScrollPane(); + updateTree(); + cp.add(treePane, BorderLayout.CENTER); - cp.add(refreshPanel, BorderLayout.SOUTH); - - this.refreshButton = new JButton("refresh"); - this.refreshButton.addActionListener(this); + cp.add(refreshPanel, BorderLayout.SOUTH); + + this.refreshButton = new JButton("refresh"); + this.refreshButton.addActionListener(this); refreshPanel.add(refreshButton, BorderLayout.EAST); - refreshPanel.add(autoRefresh, BorderLayout.WEST); - - this.pack(); - this.setVisible(true); - } - - - private void updateTree() { - super.setTitle("Routing Info of " + host + " at " + - SimClock.getFormattedTime(2)); - RoutingInfo ri = host.getRoutingInfo(); - DefaultMutableTreeNode top = new DefaultMutableTreeNode(ri); + refreshPanel.add(autoRefresh, BorderLayout.WEST); + + this.pack(); + this.setVisible(true); + } + + + private void updateTree() { + super.setTitle("Routing Info of " + host + " at " + + SimClock.getFormattedTime(2)); + RoutingInfo ri = host.getRoutingInfo(); + DefaultMutableTreeNode top = new DefaultMutableTreeNode(ri); Vector expanded = new Vector(); - + addChildren(top, ri); if (this.tree != null) { /* store expanded state */ @@ -77,34 +77,34 @@ private void updateTree() { } } } - + this.tree = new JTree(top); - + for (int i=0; i < this.tree.getRowCount(); i++) { /* restore expanded */ - if (expanded.size() > 0 && expanded.firstElement() == i) { + if (expanded.size() > 0 && expanded.firstElement() == i) { this.tree.expandRow(i); expanded.remove(0); - } - } - - this.treePane.setViewportView(this.tree); - this.treePane.revalidate(); - } - - - private void addChildren(DefaultMutableTreeNode node, RoutingInfo info) { - for (RoutingInfo ri : info.getMoreInfo()) { - DefaultMutableTreeNode child = new DefaultMutableTreeNode(ri); - node.add(child); - // recursively add children of this info - addChildren(child, ri); - } - } - + } + } + + this.treePane.setViewportView(this.tree); + this.treePane.revalidate(); + } + + + private void addChildren(DefaultMutableTreeNode node, RoutingInfo info) { + for (RoutingInfo ri : info.getMoreInfo()) { + DefaultMutableTreeNode child = new DefaultMutableTreeNode(ri); + node.add(child); + // recursively add children of this info + addChildren(child, ri); + } + } + public void actionPerformed(ActionEvent e) { - Object s = e.getSource(); - if (s == this.refreshButton || s == this.refreshTimer) { - updateTree(); + Object s = e.getSource(); + if (s == this.refreshButton || s == this.refreshTimer) { + updateTree(); } if (e.getSource() == this.autoRefresh) { if (this.autoRefresh.isSelected()) { @@ -113,7 +113,7 @@ public void actionPerformed(ActionEvent e) { } else { this.refreshTimer.stop(); } - } + } } - -} \ No newline at end of file + +} diff --git a/gui/SimMenuBar.java b/gui/SimMenuBar.java index dff5a5250..44d528885 100644 --- a/gui/SimMenuBar.java +++ b/gui/SimMenuBar.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package gui; @@ -34,7 +34,7 @@ public class SimMenuBar extends JMenuBar implements ActionListener { /** title of the about window */ public static final String ABOUT_TITLE = "about ONE"; /** GPLv3 license text for about window */ - public static final String ABOUT_TEXT = + public static final String ABOUT_TEXT = "Copyright (C) 2007-2011 Aalto University, Comnet\n\n"+ "This program is free software: you can redistribute it and/or modify\n"+ "it under the terms of the GNU General Public License as published by\n"+ @@ -47,7 +47,7 @@ public class SimMenuBar extends JMenuBar implements ActionListener { "You should have received a copy of the GNU General Public License\n"+ "along with this program. If not, see .\n\n"+ "Map data copyright: Maanmittauslaitos, 2007"; - + private JCheckBoxMenuItem enableBgImage; private JCheckBoxMenuItem showNodeName; private JCheckBoxMenuItem showNodeCoverage; @@ -57,11 +57,11 @@ public class SimMenuBar extends JMenuBar implements ActionListener { private JCheckBoxMenuItem enableMapGraphic; private JCheckBoxMenuItem autoClearOverlay; private JCheckBoxMenuItem focusOnClick; - + private JMenuItem clearOverlay; private JMenuItem addNodeMessageFilter; private JMenuItem clearNodeFilters; - + private JMenuItem about; private PlayField field; private NodeChooser chooser; @@ -78,7 +78,7 @@ public class SimMenuBar extends JMenuBar implements ActionListener { public static final String FOCUS_ON_CLICK_S = "focusOnClick"; /** The namespace where underlay image -related settings are found */ public static final String UNDERLAY_NS = "GUI.UnderlayImage"; - + public SimMenuBar(PlayField field, NodeChooser nodeChooser) { this.field = field; this.chooser = nodeChooser; @@ -91,18 +91,18 @@ private void init() { JMenu help = new JMenu("Help"); JMenu nodeFilters = new JMenu("Add node filter"); Settings settings = new Settings(UNDERLAY_NS); - + if (settings.contains("fileName")) { - // create underlay image menu item only if filename is specified + // create underlay image menu item only if filename is specified enableBgImage = createCheckItem(pfMenu,"Show underlay image", false, null); } - + settings.setNameSpace(gui.MainWindow.GUI_NS); - + showNodeName = createCheckItem(pfMenu, "Show node name strings", - true, SHOW_NODE_NAMESTR_S); - showNodeCoverage = createCheckItem(pfMenu, + true, SHOW_NODE_NAMESTR_S); + showNodeCoverage = createCheckItem(pfMenu, "Show node radio coverages", true, SHOW_RADIO_COVERAGES_S); showNodeConnections = createCheckItem(pfMenu, "Show node connections", true, SHOW_CONNECTIONS_S); @@ -116,58 +116,58 @@ private void init() { autoClearOverlay = createCheckItem(pfMenu, "Autoclear overlay", true, null); clearOverlay = createMenuItem(pfToolsMenu, "Clear overlays"); - - + + pfToolsMenu.addSeparator(); addNodeMessageFilter = createMenuItem(nodeFilters, "message filter"); pfToolsMenu.add(nodeFilters); clearNodeFilters = createMenuItem(pfToolsMenu, "Clear node filters"); updatePlayfieldSettings(); - + about = createMenuItem(help,"about"); this.add(pfMenu); this.add(pfToolsMenu); this.add(Box.createHorizontalGlue()); this.add(help); } - + private JMenuItem createMenuItem(Container c, String txt) { JMenuItem i = new JMenuItem(txt); i.addActionListener(this); c.add(i); return i; } - + /** * Creates a new check box menu item to the given container * @param c The container * @param txt Text for the menu item * @param selected Is the check box selected (by default) - * @param setting Name of the setting where the check-box-selected - * true/false value is read from (if not found, the "selected" parameter - * value is used). If null, no setting is read and the default is + * @param setting Name of the setting where the check-box-selected + * true/false value is read from (if not found, the "selected" parameter + * value is used). If null, no setting is read and the default is * used as such. * @return The created check box menu item */ - private JCheckBoxMenuItem createCheckItem(Container c,String txt, + private JCheckBoxMenuItem createCheckItem(Container c,String txt, boolean selected, String setting) { Settings s = new Settings(gui.MainWindow.GUI_NS); - + JCheckBoxMenuItem i = new JCheckBoxMenuItem(txt); if (setting == null) { i.setSelected(selected); } else { i.setSelected(s.getBoolean(setting, selected)); } - + i.addActionListener(this); c.add(i); - + return i; } - + private void updatePlayfieldSettings() { NodeGraphic.setDrawNodeName(showNodeName.isSelected()); NodeGraphic.setDrawCoverage(showNodeCoverage.isSelected()); @@ -177,18 +177,18 @@ private void updatePlayfieldSettings() { field.setAutoClearOverlay(autoClearOverlay.isSelected()); field.setFocusOnClick(focusOnClick.isSelected()); } - + private String getFilterString(String message) { return (String)JOptionPane.showInputDialog( this, message, "Filter input", JOptionPane.PLAIN_MESSAGE); } - + public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == enableBgImage) { toggleUnderlayImage(); } - else if (source == this.showNodeName || + else if (source == this.showNodeName || source == this.showNodeCoverage || source == this.showNodeConnections || source == this.enableMapGraphic || @@ -209,11 +209,11 @@ else if (source == clearNodeFilters) { chooser.clearFilters(); } else if (source == this.about) { - JOptionPane.showMessageDialog(this, ABOUT_TEXT, ABOUT_TITLE, + JOptionPane.showMessageDialog(this, ABOUT_TEXT, ABOUT_TITLE, JOptionPane.INFORMATION_MESSAGE); } } - + /** * Toggles the showing of underlay image. Image is read from the file only * when it is enabled to save some memory. @@ -232,15 +232,15 @@ private void toggleUnderlayImage() { rotate = settings.getDouble("rotate"); image = ImageIO.read(new File(imgFile)); } catch (IOException ex) { - warn("Couldn't set underlay image " + imgFile + ". " + - ex.getMessage()); - enableBgImage.setSelected(false); - return; + warn("Couldn't set underlay image " + imgFile + ". " + + ex.getMessage()); + enableBgImage.setSelected(false); + return; } catch (SettingsError er) { - warn("Problem with the underlay image settings: " + - er.getMessage()); - return; + warn("Problem with the underlay image settings: " + + er.getMessage()); + return; } field.setUnderlayImage(image, offsets[0], offsets[1], scale, rotate); @@ -250,10 +250,10 @@ private void toggleUnderlayImage() { field.setUnderlayImage(null, 0, 0, 0, 0); } } - + private void warn(String txt) { - JOptionPane.showMessageDialog(null, txt, "warning", + JOptionPane.showMessageDialog(null, txt, "warning", JOptionPane.WARNING_MESSAGE); } - -} \ No newline at end of file + +} diff --git a/gui/nodefilter/NodeFilter.java b/gui/nodefilter/NodeFilter.java index 4b8f634f3..92a3d4b7f 100644 --- a/gui/nodefilter/NodeFilter.java +++ b/gui/nodefilter/NodeFilter.java @@ -1,26 +1,26 @@ -/* - * Copyright 2011 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ - -package gui.nodefilter; - -import core.DTNHost; - -/** - * Interface for node filtering classes - */ -public interface NodeFilter { - - /** - * Returns true if the given node should be included in the filtered set - * @param node The node to check - * @return true if the node should be included, false if not - */ - public boolean filterNode(DTNHost node); - - /** - * Returns a String presentations of the filter - */ - public String toString(); -} +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package gui.nodefilter; + +import core.DTNHost; + +/** + * Interface for node filtering classes + */ +public interface NodeFilter { + + /** + * Returns true if the given node should be included in the filtered set + * @param node The node to check + * @return true if the node should be included, false if not + */ + public boolean filterNode(DTNHost node); + + /** + * Returns a String presentations of the filter + */ + public String toString(); +} diff --git a/gui/nodefilter/NodeMessageFilter.java b/gui/nodefilter/NodeMessageFilter.java index a35ca3b86..520516acc 100644 --- a/gui/nodefilter/NodeMessageFilter.java +++ b/gui/nodefilter/NodeMessageFilter.java @@ -1,33 +1,33 @@ -/* - * Copyright 2011 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ - -package gui.nodefilter; - -import core.DTNHost; - -/** - * Node filter that filters nodes by the messages they have in their buffer - */ -public class NodeMessageFilter implements NodeFilter { - private String messageId; - - /** - * Creates a new filter with the given message ID - * @param messageId The message ID used for filtering - */ - public NodeMessageFilter(String messageId) { - this.messageId = messageId; - } - - public boolean filterNode(DTNHost node) { - return node.getRouter().hasMessage(messageId); - } - - @Override - public String toString() { - return "Filters nodes with message ID " + messageId; - } - -} +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package gui.nodefilter; + +import core.DTNHost; + +/** + * Node filter that filters nodes by the messages they have in their buffer + */ +public class NodeMessageFilter implements NodeFilter { + private String messageId; + + /** + * Creates a new filter with the given message ID + * @param messageId The message ID used for filtering + */ + public NodeMessageFilter(String messageId) { + this.messageId = messageId; + } + + public boolean filterNode(DTNHost node) { + return node.getRouter().hasMessage(messageId); + } + + @Override + public String toString() { + return "Filters nodes with message ID " + messageId; + } + +} diff --git a/gui/package.html b/gui/package.html index 308cdd55a..3196fe0d1 100644 --- a/gui/package.html +++ b/gui/package.html @@ -1,8 +1,8 @@ - - - - -Contains the classes of Graphical User Interface. - - - \ No newline at end of file + + + + +Contains the classes of Graphical User Interface. + + + diff --git a/gui/playfield/MapGraphic.java b/gui/playfield/MapGraphic.java index 1ceb5a057..8e94f82cc 100644 --- a/gui/playfield/MapGraphic.java +++ b/gui/playfield/MapGraphic.java @@ -1,53 +1,53 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui.playfield; - +package gui.playfield; + import java.awt.Color; import java.awt.Graphics2D; import movement.map.MapNode; import movement.map.SimMap; import core.Coord; - -/** - * PlayfieldGraphic for SimMap visualization - * - */ -public class MapGraphic extends PlayFieldGraphic { - private SimMap simMap; - private final Color PATH_COLOR = Color.LIGHT_GRAY; - private final Color BG_COLOR = Color.WHITE; - - public MapGraphic(SimMap simMap) { - this.simMap = simMap; - - } - - // TODO: draw only once and store to buffer - @Override - public void draw(Graphics2D g2) { - Coord c,c2; - - if (simMap == null) { - return; - } - - g2.setColor(PATH_COLOR); - g2.setBackground(BG_COLOR); - - // draws all edges between map nodes (bidirectional edges twice) - for (MapNode n : simMap.getNodes()) { - c = n.getLocation(); - - // draw a line to adjacent nodes - for (MapNode n2 : n.getNeighbors()) { - c2 = n2.getLocation(); - g2.drawLine(scale(c2.getX()), scale(c2.getY()), - scale(c.getX()), scale(c.getY())); - } - } - } - -} + +/** + * PlayfieldGraphic for SimMap visualization + * + */ +public class MapGraphic extends PlayFieldGraphic { + private SimMap simMap; + private final Color PATH_COLOR = Color.LIGHT_GRAY; + private final Color BG_COLOR = Color.WHITE; + + public MapGraphic(SimMap simMap) { + this.simMap = simMap; + + } + + // TODO: draw only once and store to buffer + @Override + public void draw(Graphics2D g2) { + Coord c,c2; + + if (simMap == null) { + return; + } + + g2.setColor(PATH_COLOR); + g2.setBackground(BG_COLOR); + + // draws all edges between map nodes (bidirectional edges twice) + for (MapNode n : simMap.getNodes()) { + c = n.getLocation(); + + // draw a line to adjacent nodes + for (MapNode n2 : n.getNeighbors()) { + c2 = n2.getLocation(); + g2.drawLine(scale(c2.getX()), scale(c2.getY()), + scale(c.getX()), scale(c.getY())); + } + } + } + +} diff --git a/gui/playfield/MessageGraphic.java b/gui/playfield/MessageGraphic.java index 14cd8ca7f..618c1fbac 100644 --- a/gui/playfield/MessageGraphic.java +++ b/gui/playfield/MessageGraphic.java @@ -1,43 +1,43 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui.playfield; - +package gui.playfield; + import java.awt.Color; import java.awt.Graphics2D; import java.awt.Polygon; import core.DTNHost; - -/** - * Visualization of a message - * - */ -public class MessageGraphic extends PlayFieldGraphic { - private Color msgColor = Color.RED; - - private DTNHost from; - private DTNHost to; - - public MessageGraphic(DTNHost from, DTNHost to) { - this.to = to; - this.from = from; - } - - @Override - public void draw(Graphics2D g2) { - g2.setColor(msgColor); - - int fromX = scale(from.getLocation().getX()); - int fromY = scale(from.getLocation().getY()); - int toX = scale(to.getLocation().getX()); - int toY = scale(to.getLocation().getY()); - - // line from "from host" to "to host" - Polygon p = new Polygon(new int[] {fromX, toX}, - new int[] {fromY,toY}, 2); - - g2.draw(p); - } -} + +/** + * Visualization of a message + * + */ +public class MessageGraphic extends PlayFieldGraphic { + private Color msgColor = Color.RED; + + private DTNHost from; + private DTNHost to; + + public MessageGraphic(DTNHost from, DTNHost to) { + this.to = to; + this.from = from; + } + + @Override + public void draw(Graphics2D g2) { + g2.setColor(msgColor); + + int fromX = scale(from.getLocation().getX()); + int fromY = scale(from.getLocation().getY()); + int toX = scale(to.getLocation().getX()); + int toY = scale(to.getLocation().getY()); + + // line from "from host" to "to host" + Polygon p = new Polygon(new int[] {fromX, toX}, + new int[] {fromY,toY}, 2); + + g2.draw(p); + } +} diff --git a/gui/playfield/NodeGraphic.java b/gui/playfield/NodeGraphic.java index dc746deff..8bac8a1f4 100644 --- a/gui/playfield/NodeGraphic.java +++ b/gui/playfield/NodeGraphic.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui.playfield; - +package gui.playfield; + import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.Ellipse2D; @@ -14,41 +14,41 @@ import core.Coord; import core.DTNHost; import core.NetworkInterface; - -/** - * Visualization of a DTN Node - * - */ -public class NodeGraphic extends PlayFieldGraphic { - private static boolean drawCoverage; - private static boolean drawNodeName; + +/** + * Visualization of a DTN Node + * + */ +public class NodeGraphic extends PlayFieldGraphic { + private static boolean drawCoverage; + private static boolean drawNodeName; private static boolean drawConnections; - private static boolean drawBuffer; + private static boolean drawBuffer; private static List highlightedNodes; - - private static Color rangeColor = Color.GREEN; - private static Color conColor = Color.BLACK; - private static Color hostColor = Color.BLUE; - private static Color hostNameColor = Color.BLUE; - private static Color msgColor1 = Color.BLUE; - private static Color msgColor2 = Color.GREEN; + + private static Color rangeColor = Color.GREEN; + private static Color conColor = Color.BLACK; + private static Color hostColor = Color.BLUE; + private static Color hostNameColor = Color.BLUE; + private static Color msgColor1 = Color.BLUE; + private static Color msgColor2 = Color.GREEN; private static Color msgColor3 = Color.RED; - - private static Color highlightedNodeColor = Color.MAGENTA; - - private DTNHost node; - - public NodeGraphic(DTNHost node) { - this.node = node; - } - - @Override - public void draw(Graphics2D g2) { + + private static Color highlightedNodeColor = Color.MAGENTA; + + private DTNHost node; + + public NodeGraphic(DTNHost node) { + this.node = node; + } + + @Override + public void draw(Graphics2D g2) { drawHost(g2); - if (drawBuffer) { + if (drawBuffer) { drawMessages(g2); - } - } + } + } /** * @return true if the node this graphic represents should be highlighted @@ -60,16 +60,16 @@ private boolean isHighlighted() { return highlightedNodes.contains(node); } } - - /** - * Visualize node's location, radio ranges and connections - * @param g2 The graphic context to draw to - */ - private void drawHost(Graphics2D g2) { - Coord loc = node.getLocation(); - - if (drawCoverage && node.isRadioActive()) { - ArrayList interfaces = + + /** + * Visualize node's location, radio ranges and connections + * @param g2 The graphic context to draw to + */ + private void drawHost(Graphics2D g2) { + Coord loc = node.getLocation(); + + if (drawCoverage && node.isRadioActive()) { + ArrayList interfaces = new ArrayList(); interfaces.addAll(node.getInterfaces()); for (NetworkInterface ni : interfaces) { @@ -77,132 +77,132 @@ private void drawHost(Graphics2D g2) { Ellipse2D.Double coverage; coverage = new Ellipse2D.Double(scale(loc.getX()-range), - scale(loc.getY()-range), scale(range * 2), - scale(range * 2)); + scale(loc.getY()-range), scale(range * 2), + scale(range * 2)); // draw the "range" circle g2.setColor(rangeColor); g2.draw(coverage); } - } - - if (drawConnections) { - g2.setColor(conColor); - Coord c1 = node.getLocation(); - ArrayList conList = new ArrayList(); - // create a copy to prevent concurrent modification exceptions - conList.addAll(node.getConnections()); + } + + if (drawConnections) { + g2.setColor(conColor); + Coord c1 = node.getLocation(); + ArrayList conList = new ArrayList(); + // create a copy to prevent concurrent modification exceptions + conList.addAll(node.getConnections()); for (Connection c : conList) { DTNHost otherNode = c.getOtherNode(node); Coord c2; - + if (otherNode == null) { continue; /* disconnected before drawn */ - } - c2 = otherNode.getLocation(); - g2.drawLine(scale(c1.getX()), scale(c1.getY()), - scale(c2.getX()), scale(c2.getY())); - } - } + } + c2 = otherNode.getLocation(); + g2.drawLine(scale(c1.getX()), scale(c1.getY()), + scale(c2.getX()), scale(c2.getY())); + } + } /* draw node rectangle */ - g2.setColor(hostColor); - g2.drawRect(scale(loc.getX()-1),scale(loc.getY()-1), + g2.setColor(hostColor); + g2.drawRect(scale(loc.getX()-1),scale(loc.getY()-1), scale(2),scale(2)); if (isHighlighted()) { g2.setColor(highlightedNodeColor); - g2.fillRect(scale(loc.getX()) - 3 ,scale(loc.getY()) - 3, 6, 6); + g2.fillRect(scale(loc.getX()) - 3 ,scale(loc.getY()) - 3, 6, 6); } - - if (drawNodeName) { - g2.setColor(hostNameColor); - // Draw node's address next to it - g2.drawString(node.toString(), scale(loc.getX()), - scale(loc.getY())); - } - } - - /** - * Sets whether radio coverage of nodes should be drawn - * @param draw If true, radio coverage is drawn - */ - public static void setDrawCoverage(boolean draw) { - drawCoverage = draw; - } - - /** - * Sets whether node's name should be displayed - * @param draw If true, node's name is displayed - */ - public static void setDrawNodeName(boolean draw) { - drawNodeName = draw; - } - - /** - * Sets whether node's connections to other nodes should be drawn - * @param draw If true, node's connections to other nodes is drawn - */ - public static void setDrawConnections(boolean draw) { - drawConnections = draw; + + if (drawNodeName) { + g2.setColor(hostNameColor); + // Draw node's address next to it + g2.drawString(node.toString(), scale(loc.getX()), + scale(loc.getY())); + } + } + + /** + * Sets whether radio coverage of nodes should be drawn + * @param draw If true, radio coverage is drawn + */ + public static void setDrawCoverage(boolean draw) { + drawCoverage = draw; } - + + /** + * Sets whether node's name should be displayed + * @param draw If true, node's name is displayed + */ + public static void setDrawNodeName(boolean draw) { + drawNodeName = draw; + } + + /** + * Sets whether node's connections to other nodes should be drawn + * @param draw If true, node's connections to other nodes is drawn + */ + public static void setDrawConnections(boolean draw) { + drawConnections = draw; + } + /** * Sets whether node's message buffer is shown - * @param draw If true, node's message buffer is drawn + * @param draw If true, node's message buffer is drawn */ public static void setDrawBuffer(boolean draw) { drawBuffer = draw; } - + public static void setHighlightedNodes(List nodes) { highlightedNodes = nodes; - } - - /** - * Visualize the messages this node is carrying - * @param g2 The graphic context to draw to - */ - private void drawMessages(Graphics2D g2) { - int nrofMessages = node.getNrofMessages(); - Coord loc = node.getLocation(); - - drawBar(g2,loc, nrofMessages % 10, 1); - drawBar(g2,loc, nrofMessages / 10, 2); - } - - /** - * Draws a bar (stack of squares) next to a location - * @param g2 The graphic context to draw to - * @param loc The location where to draw - * @param nrof How many squares in the stack - * @param col Which column - */ - private void drawBar(Graphics2D g2, Coord loc, int nrof, int col) { - final int BAR_HEIGHT = 5; - final int BAR_WIDTH = 5; - final int BAR_DISPLACEMENT = 2; - - // draws a stack of squares next loc - for (int i=1; i <= nrof; i++) { - if (i%2 == 0) { // use different color for every other msg - g2.setColor(msgColor1); - } - else { - if (col > 1) { - g2.setColor(msgColor3); - } - else { - g2.setColor(msgColor2); - } - } - - g2.fillRect(scale(loc.getX()-BAR_DISPLACEMENT-(BAR_WIDTH*col)), - scale(loc.getY()- BAR_DISPLACEMENT- i* BAR_HEIGHT), - scale(BAR_WIDTH), scale(BAR_HEIGHT)); - } - - } - -} + } + + /** + * Visualize the messages this node is carrying + * @param g2 The graphic context to draw to + */ + private void drawMessages(Graphics2D g2) { + int nrofMessages = node.getNrofMessages(); + Coord loc = node.getLocation(); + + drawBar(g2,loc, nrofMessages % 10, 1); + drawBar(g2,loc, nrofMessages / 10, 2); + } + + /** + * Draws a bar (stack of squares) next to a location + * @param g2 The graphic context to draw to + * @param loc The location where to draw + * @param nrof How many squares in the stack + * @param col Which column + */ + private void drawBar(Graphics2D g2, Coord loc, int nrof, int col) { + final int BAR_HEIGHT = 5; + final int BAR_WIDTH = 5; + final int BAR_DISPLACEMENT = 2; + + // draws a stack of squares next loc + for (int i=1; i <= nrof; i++) { + if (i%2 == 0) { // use different color for every other msg + g2.setColor(msgColor1); + } + else { + if (col > 1) { + g2.setColor(msgColor3); + } + else { + g2.setColor(msgColor2); + } + } + + g2.fillRect(scale(loc.getX()-BAR_DISPLACEMENT-(BAR_WIDTH*col)), + scale(loc.getY()- BAR_DISPLACEMENT- i* BAR_HEIGHT), + scale(BAR_WIDTH), scale(BAR_HEIGHT)); + } + + } + +} diff --git a/gui/playfield/PathGraphic.java b/gui/playfield/PathGraphic.java index a383971f5..89ef2b57c 100644 --- a/gui/playfield/PathGraphic.java +++ b/gui/playfield/PathGraphic.java @@ -1,54 +1,54 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui.playfield; - +package gui.playfield; + import java.awt.Color; import java.awt.Graphics2D; import java.util.List; import movement.Path; import core.Coord; - -/** - * Visualization of a Path - * - */ -public class PathGraphic extends PlayFieldGraphic { - private final static Color PATH_COLOR = Color.RED; - private List coords; - - public PathGraphic(Path path) { - if (path == null) { - this.coords = null; - } - else { - this.coords = path.getCoords(); - assert this.coords != null && this.coords.size() > 0 : - "No coordinates in the path (" + path + ")"; - } - } - - /** - * Draws a line trough all path's coordinates. - * @param g2 The graphics context to draw to - */ - @Override - public void draw(Graphics2D g2) { - if (coords == null) { - return; - } - - g2.setColor(PATH_COLOR); - Coord prev = coords.get(0); - - for (int i=1, n=coords.size(); i < n; i++) { - Coord next = coords.get(i); - g2.drawLine(scale(prev.getX()), scale(prev.getY()), - scale(next.getX()), scale(next.getY())); - prev = next; - } - } - -} + +/** + * Visualization of a Path + * + */ +public class PathGraphic extends PlayFieldGraphic { + private final static Color PATH_COLOR = Color.RED; + private List coords; + + public PathGraphic(Path path) { + if (path == null) { + this.coords = null; + } + else { + this.coords = path.getCoords(); + assert this.coords != null && this.coords.size() > 0 : + "No coordinates in the path (" + path + ")"; + } + } + + /** + * Draws a line trough all path's coordinates. + * @param g2 The graphics context to draw to + */ + @Override + public void draw(Graphics2D g2) { + if (coords == null) { + return; + } + + g2.setColor(PATH_COLOR); + Coord prev = coords.get(0); + + for (int i=1, n=coords.size(); i < n; i++) { + Coord next = coords.get(i); + g2.drawLine(scale(prev.getX()), scale(prev.getY()), + scale(next.getX()), scale(next.getY())); + prev = next; + } + } + +} diff --git a/gui/playfield/PlayField.java b/gui/playfield/PlayField.java index a562041e4..5630ce079 100644 --- a/gui/playfield/PlayField.java +++ b/gui/playfield/PlayField.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package gui.playfield; - +package gui.playfield; + import gui.DTNSimGUI; import java.awt.Color; @@ -25,137 +25,137 @@ import core.Coord; import core.DTNHost; import core.World; - -/** - * The canvas where node graphics and message visualizations are drawn. - * - */ + +/** + * The canvas where node graphics and message visualizations are drawn. + * + */ public class PlayField extends JPanel { public static final int PLAYFIELD_OFFSET = 10; - - private World w; + + private World w; private DTNSimGUI gui; - - private Color bgColor = Color.WHITE; - - private List overlayGraphics; - private boolean autoClearOverlay; // automatically clear overlay graphics - private MapGraphic mapGraphic; - private boolean showMapGraphic; + + private Color bgColor = Color.WHITE; + + private List overlayGraphics; + private boolean autoClearOverlay; // automatically clear overlay graphics + private MapGraphic mapGraphic; + private boolean showMapGraphic; private ScaleReferenceGraphic refGraphic; - private boolean focusOnClick; - - private BufferedImage underlayImage; - private AffineTransform imageTransform; - private AffineTransform curTransform; - private double underlayImgDx; - private double underlayImgDy; - - /** - * Creates a playfield - * @param w The world that contains the actors to be drawn - */ - public PlayField (World w, DTNSimGUI gui) { + private boolean focusOnClick; + + private BufferedImage underlayImage; + private AffineTransform imageTransform; + private AffineTransform curTransform; + private double underlayImgDx; + private double underlayImgDy; + + /** + * Creates a playfield + * @param w The world that contains the actors to be drawn + */ + public PlayField (World w, DTNSimGUI gui) { this.w = w; this.gui = gui; - - this.refGraphic = new ScaleReferenceGraphic(); - updateFieldSize(); - this.setBackground(bgColor); - this.overlayGraphics = Collections.synchronizedList( - new ArrayList()); - this.mapGraphic = null; - this.underlayImage = null; - this.imageTransform = null; + + this.refGraphic = new ScaleReferenceGraphic(); + updateFieldSize(); + this.setBackground(bgColor); + this.overlayGraphics = Collections.synchronizedList( + new ArrayList()); + this.mapGraphic = null; + this.underlayImage = null; + this.imageTransform = null; this.autoClearOverlay = true; - - this.addMouseListener(new MouseAdapter() { + + this.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (focusOnClick) { focusClosestNode(e.getX(), e.getY()); } } - }); - } - - /** - * Schedule the play field to be drawn - */ - public void updateField() { - this.repaint(); - } - - /** - * Sets an image to show under the host graphics - * @param image The image to set or null to remove the image - * @param dx X offset of the image - * @param dy Y offset of the image - * @param scale Image scaling factor - * @param rotation Rotatation angle of the image (radians) - */ - public void setUnderlayImage(BufferedImage image, - double dx, double dy, double scale, double rotation) { - if (image == null) { - this.underlayImage = null; - this.imageTransform = null; - this.curTransform = null; - return; - } - this.underlayImage = image; - this.imageTransform = AffineTransform.getRotateInstance(rotation); - this.imageTransform.scale(scale, scale); - this.curTransform = new AffineTransform(imageTransform); - this.underlayImgDx = dx; - this.underlayImgDy = dy; - - curTransform.scale(PlayFieldGraphic.getScale(), - PlayFieldGraphic.getScale()); - curTransform.translate(this.underlayImgDx, this.underlayImgDy); - - } - - /** - * Sets the zooming/scaling factor - * @param scale The new scale - */ - public void setScale(double scale) { - PlayFieldGraphic.setScale(scale); - this.updateFieldSize(); - if (this.imageTransform != null) { - this.curTransform = new AffineTransform(imageTransform); - curTransform.scale(scale, scale); - curTransform.translate(this.underlayImgDx, this.underlayImgDy); - } - } - - /** - * Sets the source for the map graphics and enables map graphics showing - * @param simMap The map to show - */ - public void setMap(SimMap simMap) { - this.mapGraphic = new MapGraphic(simMap); - this.showMapGraphic = true; - } - - /** - * Enables/disables showing of map graphics - * @param show True if the map graphics should be shown (false if not) - */ - public void setShowMapGraphic(boolean show) { - this.showMapGraphic = show; - } - - /** - * Enables or disables the automatic clearing of overlay graphics. - * If enabled, overlay graphics are cleared every time a new graphics - * object is set to be drawn. - * @param clear Auto clear is enabled if this is true, disabled on false - */ - public void setAutoClearOverlay(boolean clear) { - this.autoClearOverlay = clear; - } - + }); + } + + /** + * Schedule the play field to be drawn + */ + public void updateField() { + this.repaint(); + } + + /** + * Sets an image to show under the host graphics + * @param image The image to set or null to remove the image + * @param dx X offset of the image + * @param dy Y offset of the image + * @param scale Image scaling factor + * @param rotation Rotatation angle of the image (radians) + */ + public void setUnderlayImage(BufferedImage image, + double dx, double dy, double scale, double rotation) { + if (image == null) { + this.underlayImage = null; + this.imageTransform = null; + this.curTransform = null; + return; + } + this.underlayImage = image; + this.imageTransform = AffineTransform.getRotateInstance(rotation); + this.imageTransform.scale(scale, scale); + this.curTransform = new AffineTransform(imageTransform); + this.underlayImgDx = dx; + this.underlayImgDy = dy; + + curTransform.scale(PlayFieldGraphic.getScale(), + PlayFieldGraphic.getScale()); + curTransform.translate(this.underlayImgDx, this.underlayImgDy); + + } + + /** + * Sets the zooming/scaling factor + * @param scale The new scale + */ + public void setScale(double scale) { + PlayFieldGraphic.setScale(scale); + this.updateFieldSize(); + if (this.imageTransform != null) { + this.curTransform = new AffineTransform(imageTransform); + curTransform.scale(scale, scale); + curTransform.translate(this.underlayImgDx, this.underlayImgDy); + } + } + + /** + * Sets the source for the map graphics and enables map graphics showing + * @param simMap The map to show + */ + public void setMap(SimMap simMap) { + this.mapGraphic = new MapGraphic(simMap); + this.showMapGraphic = true; + } + + /** + * Enables/disables showing of map graphics + * @param show True if the map graphics should be shown (false if not) + */ + public void setShowMapGraphic(boolean show) { + this.showMapGraphic = show; + } + + /** + * Enables or disables the automatic clearing of overlay graphics. + * If enabled, overlay graphics are cleared every time a new graphics + * object is set to be drawn. + * @param clear Auto clear is enabled if this is true, disabled on false + */ + public void setAutoClearOverlay(boolean clear) { + this.autoClearOverlay = clear; + } + /** * Enables or disables the automatic clearing of overlay graphics. * If enabled, overlay graphics are cleared every time a new graphics @@ -165,124 +165,124 @@ public void setAutoClearOverlay(boolean clear) { public void setFocusOnClick(boolean focus) { this.focusOnClick = focus; } - - /** - * Draws the play field. To be called by Swing framework or directly if - * different context than screen is desired - * @param g The graphics context to draw the field to - */ - public void paint(Graphics g) { - Graphics2D g2 = (Graphics2D)g; - g2.setBackground(bgColor); - + + /** + * Draws the play field. To be called by Swing framework or directly if + * different context than screen is desired + * @param g The graphics context to draw the field to + */ + public void paint(Graphics g) { + Graphics2D g2 = (Graphics2D)g; + g2.setBackground(bgColor); + g2.translate(PLAYFIELD_OFFSET, PLAYFIELD_OFFSET); - - // clear old playfield graphics - g2.clearRect(-PLAYFIELD_OFFSET, -PLAYFIELD_OFFSET, - this.getWidth() + PLAYFIELD_OFFSET, - this.getHeight() + PLAYFIELD_OFFSET); - if (underlayImage != null) { - g2.drawImage(underlayImage,curTransform, null); - } - - // draw map (is exists and drawing requested) - if (mapGraphic != null && showMapGraphic) { - mapGraphic.draw(g2); - } - - // draw hosts - for (DTNHost h : w.getHosts()) { - new NodeGraphic(h).draw(g2); - } - - // draw overlay graphics - for (int i=0, n=overlayGraphics.size(); i - - - -Contains the classes of Graphical User Interface's playfield -view -(the graphical presentation of the nodes' locations and other information). - - - \ No newline at end of file + + + + +Contains the classes of Graphical User Interface's playfield -view +(the graphical presentation of the nodes' locations and other information). + + + diff --git a/input/BinaryEventsReader.java b/input/BinaryEventsReader.java index b51b038cc..5612dda78 100644 --- a/input/BinaryEventsReader.java +++ b/input/BinaryEventsReader.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - +package input; + import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -14,124 +14,124 @@ import java.util.List; import core.SimError; - -/** - * Reads External Events from a binary file. Can also create binary files - * from a list of external events. - */ -public class BinaryEventsReader implements ExternalEventsReader { - /** Extension of binary external events file */ - public static final String BINARY_EXT = ".binee"; - - private ObjectInputStream in; - private int eventsLeft; - - /** - * Constructor. - * @param eventsFile The file where the events are read - */ - public BinaryEventsReader(File eventsFile) { - try { - FileInputStream fis = new FileInputStream(eventsFile); - in = new ObjectInputStream(fis); - // first object should tell the amount of events - eventsLeft = (Integer)in.readObject(); - } catch (IOException e) { - throw new SimError(e); - } catch (ClassNotFoundException e) { - throw new SimError("Invalid binary input file for external " + - "events:" + eventsFile.getAbsolutePath(), e); - } - - } - - /** - * Read events from a binary file created with storeBinaryFile method - * @param nrof Maximum number of events to read - * @return Events in an ArrayList (empty list if didn't read any) - * @see #storeToBinaryFile(String, List) - */ - @SuppressWarnings("unchecked") // suppress cast warnings - public List readEvents(int nrof) { - ArrayList events = new ArrayList(nrof); - - if (eventsLeft == 0) { - return events; - } - - try { - for (int i=0; i < nrof && eventsLeft > 0; i++) { - events.add((ExternalEvent)in.readObject()); - eventsLeft--; - } - if (eventsLeft == 0) { - in.close(); - } - } catch (Exception e) { // FIXME: quick 'n' dirty exception handling - throw new SimError(e); - } - return events; - } - - /** - * Checks if the given file is a binary external events file - * @param file The file to check - * @return True if the file is a binary ee file, false if not - */ - public static boolean isBinaryEeFile(File file) { - if (!file.getName().endsWith(BINARY_EXT)) { - return false; - } - - // extension matches, try to read an event - try { - BinaryEventsReader r = new BinaryEventsReader(file); - r.readEvents(1); - r.close(); - } - catch (SimError e) { - return false; // read failed -> not a valid file - } - - return true; // seems to be a valid binary ee file - } - - /** - * Stores the events to a binary file - * @param fileName Path to the file where the events are stored - * @param events List of events to store - * @throws IOException if something in storing went wrong - */ - public static void storeToBinaryFile(String fileName, - List events) throws IOException { - - // make sure the file name ends with binary extension - if (!fileName.endsWith(BINARY_EXT)) { - fileName += "BINARY_EXT"; - } - - ObjectOutputStream out; - FileOutputStream fos = new FileOutputStream(fileName); - out = new ObjectOutputStream(fos); - - // store the number of events - out.writeObject(new Integer(events.size())); - - // store events - for (ExternalEvent ee : events) { - out.writeObject(ee); - } - - out.close(); - } - - public void close() { - try { - this.in.close(); - } - catch (IOException ioe) { - throw new SimError(ioe); - } - } - -} + +/** + * Reads External Events from a binary file. Can also create binary files + * from a list of external events. + */ +public class BinaryEventsReader implements ExternalEventsReader { + /** Extension of binary external events file */ + public static final String BINARY_EXT = ".binee"; + + private ObjectInputStream in; + private int eventsLeft; + + /** + * Constructor. + * @param eventsFile The file where the events are read + */ + public BinaryEventsReader(File eventsFile) { + try { + FileInputStream fis = new FileInputStream(eventsFile); + in = new ObjectInputStream(fis); + // first object should tell the amount of events + eventsLeft = (Integer)in.readObject(); + } catch (IOException e) { + throw new SimError(e); + } catch (ClassNotFoundException e) { + throw new SimError("Invalid binary input file for external " + + "events:" + eventsFile.getAbsolutePath(), e); + } + + } + + /** + * Read events from a binary file created with storeBinaryFile method + * @param nrof Maximum number of events to read + * @return Events in an ArrayList (empty list if didn't read any) + * @see #storeToBinaryFile(String, List) + */ + @SuppressWarnings("unchecked") // suppress cast warnings + public List readEvents(int nrof) { + ArrayList events = new ArrayList(nrof); + + if (eventsLeft == 0) { + return events; + } + + try { + for (int i=0; i < nrof && eventsLeft > 0; i++) { + events.add((ExternalEvent)in.readObject()); + eventsLeft--; + } + if (eventsLeft == 0) { + in.close(); + } + } catch (Exception e) { // FIXME: quick 'n' dirty exception handling + throw new SimError(e); + } + return events; + } + + /** + * Checks if the given file is a binary external events file + * @param file The file to check + * @return True if the file is a binary ee file, false if not + */ + public static boolean isBinaryEeFile(File file) { + if (!file.getName().endsWith(BINARY_EXT)) { + return false; + } + + // extension matches, try to read an event + try { + BinaryEventsReader r = new BinaryEventsReader(file); + r.readEvents(1); + r.close(); + } + catch (SimError e) { + return false; // read failed -> not a valid file + } + + return true; // seems to be a valid binary ee file + } + + /** + * Stores the events to a binary file + * @param fileName Path to the file where the events are stored + * @param events List of events to store + * @throws IOException if something in storing went wrong + */ + public static void storeToBinaryFile(String fileName, + List events) throws IOException { + + // make sure the file name ends with binary extension + if (!fileName.endsWith(BINARY_EXT)) { + fileName += "BINARY_EXT"; + } + + ObjectOutputStream out; + FileOutputStream fos = new FileOutputStream(fileName); + out = new ObjectOutputStream(fos); + + // store the number of events + out.writeObject(new Integer(events.size())); + + // store events + for (ExternalEvent ee : events) { + out.writeObject(ee); + } + + out.close(); + } + + public void close() { + try { + this.in.close(); + } + catch (IOException ioe) { + throw new SimError(ioe); + } + } + +} diff --git a/input/ConnectionEvent.java b/input/ConnectionEvent.java index e5f616aa7..d4f412d68 100644 --- a/input/ConnectionEvent.java +++ b/input/ConnectionEvent.java @@ -1,54 +1,54 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; +package input; import core.DTNHost; import core.World; - -/** - * A connection up/down event. - */ -public class ConnectionEvent extends ExternalEvent { - /** address of the node the (dis)connection is from */ - protected int fromAddr; - /** address of the node the (dis)connection is to */ - protected int toAddr; - /** Is this a "connection up" event*/ + +/** + * A connection up/down event. + */ +public class ConnectionEvent extends ExternalEvent { + /** address of the node the (dis)connection is from */ + protected int fromAddr; + /** address of the node the (dis)connection is to */ + protected int toAddr; + /** Is this a "connection up" event*/ protected boolean isUp; /** What is the interface number for this event*/ - protected String interfaceId; - - /** - * Creates a new connection event - * @param from End point of connection + protected String interfaceId; + + /** + * Creates a new connection event + * @param from End point of connection * @param to Another end of connection - * @param interf The number of interface for the connection + * @param interf The number of interface for the connection * @param up If true, this was a "connection up" event, if false, this - * was a "connection down" event - * @param time Time when the Connection event occurs - */ - public ConnectionEvent(int from, int to, String interf, boolean up, double time) { + * was a "connection down" event + * @param time Time when the Connection event occurs + */ + public ConnectionEvent(int from, int to, String interf, boolean up, double time) { super(time); - assert to != from : "Can't self connect"; - this.fromAddr = from; - this.toAddr= to; + assert to != from : "Can't self connect"; + this.fromAddr = from; + this.toAddr= to; this.isUp = up; - this.interfaceId = interf; - } - + this.interfaceId = interf; + } + @Override public void processEvent(World world) { DTNHost from = world.getNodeByAddress(this.fromAddr); DTNHost to = world.getNodeByAddress(this.toAddr); - + from.forceConnection(to, interfaceId, this.isUp); } - - @Override - public String toString() { - return "CONN " + (isUp ? "up" : "down") + " @" + this.time + " " + - this.fromAddr+"<->"+this.toAddr; - } -} + + @Override + public String toString() { + return "CONN " + (isUp ? "up" : "down") + " @" + this.time + " " + + this.fromAddr+"<->"+this.toAddr; + } +} diff --git a/input/DTN2Events.java b/input/DTN2Events.java index ec0311648..d4b8fa87c 100644 --- a/input/DTN2Events.java +++ b/input/DTN2Events.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package input; @@ -31,16 +31,16 @@ * @author teemuk */ public class DTN2Events implements EventQueue { - + private Queue events; - - /** + + /** For keeping track of bundles we've seen in the past Due to the routing implementation in dtnd it's likely that dtnd will immediately return a bundle that is forwarded to it from the ONE. */ private Map bundle_list; - + /** * Creates a new events object. * @param s Settings @@ -50,12 +50,12 @@ public DTN2Events(Settings s) { this.bundle_list = new HashMap(); DTN2Manager.setEvents(this); } - - + + //************************************************************************// // ParserHandler // //************************************************************************// - + /** * Inner class that implements the CLA interface for receiving bundles from * dtnd. @@ -67,7 +67,7 @@ public class ParserHandler implements CLAInterface { private String c_host; private int c_port; private DTNConsoleConnection console; - + /** * Creates a new parser handler. * @param hostID ID of the host that this parser corresponds to @@ -75,24 +75,24 @@ public class ParserHandler implements CLAInterface { * @param consoleHost Hostname of the dtnd * @param consolePort Console port of the dtnd */ - public ParserHandler(int hostID, DTN2Events eventsHandler, + public ParserHandler(int hostID, DTN2Events eventsHandler, String consoleHost, int consolePort) { this.host_id = hostID; this.events = eventsHandler; this.c_host = consoleHost; this.c_port = consolePort; } - + //********************************************************************// // CLAInterface Implementation // //********************************************************************// - public BundleTransferReceipt incomingBundle(String location, + public BundleTransferReceipt incomingBundle(String location, CLAParser.BundleAttributes attributes) { FileInputStream f_in; - - CLAInterface.BundleTransferReceipt r = + + CLAInterface.BundleTransferReceipt r = new CLAInterface.BundleTransferReceipt(); - + // Open the bundle file try { f_in = new FileInputStream(new File(location)); @@ -101,7 +101,7 @@ public BundleTransferReceipt incomingBundle(String location, " (file not found)"); return r; } - + // Make a copy of the bundle String filepath = "bundles/"+Math.round(Math.random()*1000000000)+ ".bundle"; @@ -122,10 +122,10 @@ public BundleTransferReceipt incomingBundle(String location, } catch (Exception e) { // TBD } - + // Parse the bundle Bundle bundle = new Bundle(new_f); - + // Check that we haven't forwarded this bundle before if (isReg(bundle)) { r.reply = false; @@ -134,18 +134,18 @@ public BundleTransferReceipt incomingBundle(String location, } else { regMsg(bundle); } - + // Lookup the receiving host - Collection c = + Collection c = DTN2Manager.getHosts(bundle.destination_EID); if (c==null || c.isEmpty()) { - Debug.p( "Couldn't find destination matching '" + + Debug.p( "Couldn't find destination matching '" + bundle.destination_EID+"'"); r.reply = false; r.bytes_sent = 0; return r; } - + // Create a message for each matched recipient // XXX: Ideally we'd only have one message, // but ONE requires each message to have exactly one recipient @@ -153,26 +153,26 @@ public BundleTransferReceipt incomingBundle(String location, // Create a new message in the queue this.events.enqueMsg(this.host_id, e.host_id, bundle); } - + // Pretend we've transmitted the whole bundle r.reply = true; r.bytes_sent = bundle.file.length(); - + return r; } public void connected() { - /* The ECLA has been connected, we can now set it up through + /* The ECLA has been connected, we can now set it up through the console */ this.console = new DTNConsoleConnection(this.c_host, this.c_port); Thread t = new Thread(this.console); t.start(); - this.console.queue("link add one dtn:one ALWAYSON extcl " + + this.console.queue("link add one dtn:one ALWAYSON extcl " + "protocol=ONE\n"); this.console.queue("route add \"dtn://*\" one\n"); } - public boolean error(String reason, Exception exception, + public boolean error(String reason, Exception exception, boolean fatal) { return false; } @@ -183,9 +183,9 @@ public boolean parseError(String reason) { //********************************************************************// } //************************************************************************// - - - + + + //************************************************************************// // EventQueue Implementation // //************************************************************************// @@ -195,7 +195,7 @@ public ExternalEvent nextEvent() { } else return new ExternalEvent(Double.MAX_VALUE); } - + public double nextEventsTime() { if (!this.events.isEmpty()) return SimClock.getTime(); @@ -203,25 +203,25 @@ public double nextEventsTime() { return Double.MAX_VALUE; } //************************************************************************// - - + + //************************************************************************// // Public Methods // //************************************************************************// - + /** * Creates a parser handler for the given host. * @param hostID ID of the host that this parser corresponds to * @param consoleHost Hostname of the dtnd * @param consolePort Console port of the dtnd */ - public DTN2Events.ParserHandler getParserHandler(int hostID, + public DTN2Events.ParserHandler getParserHandler(int hostID, String consoleHost, int consolePort) { return new ParserHandler(hostID, this, consoleHost, consolePort); } //************************************************************************// - - + + //************************************************************************// // Private Methods // //************************************************************************// @@ -229,14 +229,14 @@ private void enqueMsg(int from, int to, Bundle bundle) { String id; id = "bundle."+from+"-"+to+"-"+bundle.creation_timestamp_time+ "-"+bundle.creation_timestamp_seq_no; - MessageCreateEvent e = new MessageCreateEvent(from, to, id, + MessageCreateEvent e = new MessageCreateEvent(from, to, id, (int)(bundle.file.length()), 0, SimClock.getTime()); synchronized (this.events) { this.events.add(e); } DTN2Manager.addBundle(id,bundle); } - + // Keep track of the bundles we've received private void regMsg(Bundle bundle) { String key = bundle.source_EID+":"+bundle.destination_EID+":"+ @@ -244,7 +244,7 @@ private void regMsg(Bundle bundle) { if (!this.bundle_list.containsKey(key)) this.bundle_list.put(key,null); } - + // Check if the bundle has been received before private boolean isReg(Bundle bundle) { String key = bundle.source_EID+":"+bundle.destination_EID+":"+ @@ -252,5 +252,5 @@ private boolean isReg(Bundle bundle) { return this.bundle_list.containsKey(key); } //************************************************************************// - + } diff --git a/input/EventQueue.java b/input/EventQueue.java index df0c67bd9..e653cb207 100644 --- a/input/EventQueue.java +++ b/input/EventQueue.java @@ -1,30 +1,30 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package input; - -/** - * Interface for event queues. Any class that is not a movement model or a - * routing module but wishes to provide events for the simulation (like creating - * messages) must implement this interface and register itself to the - * simulator. See the {@link EventQueueHandler} class for configuration - * instructions. - */ -public interface EventQueue { - - /** - * Returns the next event in the queue or ExternalEvent with time of - * double.MAX_VALUE if there are no events left. - * @return The next event - */ - public ExternalEvent nextEvent(); - - /** - * Returns next event's time or Double.MAX_VALUE if there are no - * events left in the queue. - * @return Next event's time - */ - public double nextEventsTime(); - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +/** + * Interface for event queues. Any class that is not a movement model or a + * routing module but wishes to provide events for the simulation (like creating + * messages) must implement this interface and register itself to the + * simulator. See the {@link EventQueueHandler} class for configuration + * instructions. + */ +public interface EventQueue { + + /** + * Returns the next event in the queue or ExternalEvent with time of + * double.MAX_VALUE if there are no events left. + * @return The next event + */ + public ExternalEvent nextEvent(); + + /** + * Returns next event's time or Double.MAX_VALUE if there are no + * events left in the queue. + * @return Next event's time + */ + public double nextEventsTime(); + +} diff --git a/input/EventQueueHandler.java b/input/EventQueueHandler.java index 90fa5f4d7..93fbf0d09 100644 --- a/input/EventQueueHandler.java +++ b/input/EventQueueHandler.java @@ -1,40 +1,40 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - +package input; + import java.util.ArrayList; import java.util.List; import core.Settings; - + /** *

- * Handler for managing event queues. Supports two different type of event + * Handler for managing event queues. Supports two different type of event * queues: external event queues and event generator classes. * For external event queues, the events are defined in external data * file(s) (see e.g. input.StandarEventsReader). Event generator classes * define events dynamically. Both type of event queues must implement * the input.EventQueue interface. *

- * The total number of event queues to load is defined with variable + * The total number of event queues to load is defined with variable * NROF_SETTING, e.g.
* Events.nrof = 3
- * Separate event queues are configured with syntax + * Separate event queues are configured with syntax * EventsN.variable = value e.g.:
* Events1.filePath = ee/messages.txt
* or
* Events2.class = RandomMessageGenerator *

* External event files are used when the variable PATH_SETTING - * is used to define the path to the event file and event generator class - * is loaded when the name of the class is defined with - * CLASS_SETTING. - */ -public class EventQueueHandler { - /** Event queue settings main namespace ({@value})*/ - public static final String SETTINGS_NAMESPACE = "Events"; + * is used to define the path to the event file and event generator class + * is loaded when the name of the class is defined with + * CLASS_SETTING. + */ +public class EventQueueHandler { + /** Event queue settings main namespace ({@value})*/ + public static final String SETTINGS_NAMESPACE = "Events"; /** number of event queues -setting id ({@value})*/ public static final String NROF_SETTING = "nrof"; @@ -43,22 +43,22 @@ public class EventQueueHandler { public static final String CLASS_SETTING = "class"; /** name of the package where event generator classes are looked from */ public static final String CLASS_PACKAGE = "input"; - - /** number of events to preload from file -setting id ({@value})*/ - public static final String PRELOAD_SETTING = "nrofPreload"; - /** path of external events file -setting id ({@value})*/ - public static final String PATH_SETTING = "filePath"; - - private List queues; - - /** - * Creates a new EventQueueHandler which can be queried for - * event queues. - */ - public EventQueueHandler() { + + /** number of events to preload from file -setting id ({@value})*/ + public static final String PRELOAD_SETTING = "nrofPreload"; + /** path of external events file -setting id ({@value})*/ + public static final String PATH_SETTING = "filePath"; + + private List queues; + + /** + * Creates a new EventQueueHandler which can be queried for + * event queues. + */ + public EventQueueHandler() { Settings settings = new Settings(SETTINGS_NAMESPACE); int nrof = settings.getInt(NROF_SETTING); - this.queues = new ArrayList(); + this.queues = new ArrayList(); for (int i=1; i <= nrof; i++) { Settings s = new Settings(SETTINGS_NAMESPACE + i); @@ -74,21 +74,21 @@ public EventQueueHandler() { queues.add(new ExternalEventsQueue(path, preload)); } else if (s.contains(CLASS_SETTING)) { // event generator class - String className = CLASS_PACKAGE + "." + + String className = CLASS_PACKAGE + "." + s.getSetting(CLASS_SETTING); EventQueue eq = (EventQueue)s.createIntializedObject(className); - + queues.add(eq); - } - } + } + } } - - /** + + /** * Returns all the loaded event queues * @return all the loaded event queues */ public List getEventQueues() { return this.queues; - } - -} + } + +} diff --git a/input/ExternalEvent.java b/input/ExternalEvent.java index 9a81fc86c..130067637 100644 --- a/input/ExternalEvent.java +++ b/input/ExternalEvent.java @@ -1,66 +1,66 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - +package input; + import java.io.Serializable; import core.World; - -/** - * Super class for all external events. All new classes of external events + +/** + * Super class for all external events. All new classes of external events * must extend this class. This can also be used as a dummy event if only - * an update request (and no further actions) to all hosts is needed. - */ -public class ExternalEvent implements Comparable, Serializable { - /** Time of the event (simulated seconds) */ - protected double time; - - public ExternalEvent(double time) { - this.time = time; - } - - /** - * Processes the external event. - * @param world World where the actors of the event are - */ - public void processEvent(World world) { - // this is just a dummy event - } - - /** - * Returns the time when this event should happen. - * @return Event's time - */ - public double getTime() { - return this.time; - } - - /** - * Compares two external events by their time. - * @return -1, zero, 1 if this event happens before, at the same time, - * or after the other event - * @param other The other external event - */ + * an update request (and no further actions) to all hosts is needed. + */ +public class ExternalEvent implements Comparable, Serializable { + /** Time of the event (simulated seconds) */ + protected double time; + + public ExternalEvent(double time) { + this.time = time; + } + + /** + * Processes the external event. + * @param world World where the actors of the event are + */ + public void processEvent(World world) { + // this is just a dummy event + } + + /** + * Returns the time when this event should happen. + * @return Event's time + */ + public double getTime() { + return this.time; + } + + /** + * Compares two external events by their time. + * @return -1, zero, 1 if this event happens before, at the same time, + * or after the other event + * @param other The other external event + */ public int compareTo(ExternalEvent other) { - if (this.time == other.time) { + if (this.time == other.time) { return 0; } else if (this.time < other.time) { return -1; - } + } else { return 1; - } - } - - /** - * Returns a String representation of the event - * @return a String representation of the event - */ - public String toString() { - return "ExtEvent @ " + this.time; - } - -} + } + } + + /** + * Returns a String representation of the event + * @return a String representation of the event + */ + public String toString() { + return "ExtEvent @ " + this.time; + } + +} diff --git a/input/ExternalEventsQueue.java b/input/ExternalEventsQueue.java index 108540a20..90665887d 100644 --- a/input/ExternalEventsQueue.java +++ b/input/ExternalEventsQueue.java @@ -1,51 +1,51 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - +package input; + import java.io.File; import java.util.ArrayList; import java.util.List; import core.Settings; - -/** - * Queue of external events. This class also takes care of buffering - * the events and preloading only a proper amount of them. - */ -public class ExternalEventsQueue implements EventQueue { - /** ExternalEvents namespace ({@value})*/ - public static final String SETTINGS_NAMESPACE = "ExternalEvents"; - /** number of event to preload -setting id ({@value})*/ - public static final String PRELOAD_SETTING = "nrofPreload"; - /** path of external events file -setting id ({@value})*/ + +/** + * Queue of external events. This class also takes care of buffering + * the events and preloading only a proper amount of them. + */ +public class ExternalEventsQueue implements EventQueue { + /** ExternalEvents namespace ({@value})*/ + public static final String SETTINGS_NAMESPACE = "ExternalEvents"; + /** number of event to preload -setting id ({@value})*/ + public static final String PRELOAD_SETTING = "nrofPreload"; + /** path of external events file -setting id ({@value})*/ public static final String PATH_SETTING = "filePath"; - + /** default number of preloaded events */ - public static final int DEFAULT_NROF_PRELOAD = 500; - - private File eventsFile; - private ExternalEventsReader reader; - private int nextEventIndex; - private int nrofPreload; - private List queue; - private boolean allEventsRead = false; - - /** - * Creates a new Queue from a file - * @param filePath Path to the file where the events are read from. If - * file ends with extension defined in {@link BinaryEventsReader#BINARY_EXT} - * the file is assumed to be a binary file. - * @param nrofPreload How many events to preload - * @see BinaryEventsReader#BINARY_EXT - * @see BinaryEventsReader#storeToBinaryFile(String, List) - */ - public ExternalEventsQueue(String filePath, int nrofPreload) { - setNrofPreload(nrofPreload); - init(filePath); + public static final int DEFAULT_NROF_PRELOAD = 500; + + private File eventsFile; + private ExternalEventsReader reader; + private int nextEventIndex; + private int nrofPreload; + private List queue; + private boolean allEventsRead = false; + + /** + * Creates a new Queue from a file + * @param filePath Path to the file where the events are read from. If + * file ends with extension defined in {@link BinaryEventsReader#BINARY_EXT} + * the file is assumed to be a binary file. + * @param nrofPreload How many events to preload + * @see BinaryEventsReader#BINARY_EXT + * @see BinaryEventsReader#storeToBinaryFile(String, List) + */ + public ExternalEventsQueue(String filePath, int nrofPreload) { + setNrofPreload(nrofPreload); + init(filePath); } - + /** * Create a new Queue based on the given settings: {@link #PRELOAD_SETTING} * and {@link #PATH_SETTING}. The path setting supports value filling. @@ -60,104 +60,104 @@ public ExternalEventsQueue(Settings s) { } String eeFilePath = s.valueFillString(s.getSetting(PATH_SETTING)); init(eeFilePath); - } - - /** - * Sets maximum number of events that are read when the next preload occurs + } + + /** + * Sets maximum number of events that are read when the next preload occurs * @param nrof Maximum number of events to read. If less than 1, default - * value ( {@value DEFAULT_NROF_PRELOAD} ) is used. - */ - public void setNrofPreload(int nrof) { - if (nrof < 1) { - nrof = DEFAULT_NROF_PRELOAD; - } - this.nrofPreload = nrof; - } - - private void init(String eeFilePath) { - this.eventsFile = new File(eeFilePath); - - if (BinaryEventsReader.isBinaryEeFile(eventsFile)) { - this.reader = new BinaryEventsReader(eventsFile); - } - else { - this.reader = new StandardEventsReader(eventsFile); - } - - this.queue = readEvents(nrofPreload); - this.nextEventIndex = 0; - } - - /** - * Returns next event's time or Double.MAX_VALUE if there are no - * events left - * @return Next event's time - */ - public double nextEventsTime() { - if (eventsLeftInBuffer() <= 0 ) { - // in case user request time of an event that doesn't exist - return Double.MAX_VALUE; - } - else { - return queue.get(nextEventIndex).getTime(); - } - } - - /** - * Returns the next event in the queue or ExternalEvent with time of - * double.MAX_VALUE if there are no events left - * @return The next event - */ - public ExternalEvent nextEvent() { - if (queue.size() == 0) { // no more events - return new ExternalEvent(Double.MAX_VALUE); - } - - ExternalEvent ee = queue.get(nextEventIndex); - nextEventIndex++; - - if (nextEventIndex >= queue.size()) { // ran out of events - queue = readEvents(nrofPreload); - nextEventIndex = 0; - } - - return ee; - } - - /** - * Returns the amount of events left in the buffer at the moment - * (the amount can increase later if more events are read). - * @return The amount of events left or 0 there aren't any events - */ - public int eventsLeftInBuffer() { - if (queue == null || queue.size() == 0) { - return 0; - } - else { - return this.queue.size() - this.nextEventIndex; - } - } - - - /** - * Read some events from the external events reader - * @param nrof Maximum number of events to read - * @return A List of events that were read or an empty list if no events - * could be read - */ - private List readEvents(int nrof) { - if (allEventsRead) { - return new ArrayList(0); - } - - List events = reader.readEvents(nrof); - - if (nrof > 0 && events.size() == 0) { - reader.close(); - allEventsRead = true; - } - - return events; - } - -} + * value ( {@value DEFAULT_NROF_PRELOAD} ) is used. + */ + public void setNrofPreload(int nrof) { + if (nrof < 1) { + nrof = DEFAULT_NROF_PRELOAD; + } + this.nrofPreload = nrof; + } + + private void init(String eeFilePath) { + this.eventsFile = new File(eeFilePath); + + if (BinaryEventsReader.isBinaryEeFile(eventsFile)) { + this.reader = new BinaryEventsReader(eventsFile); + } + else { + this.reader = new StandardEventsReader(eventsFile); + } + + this.queue = readEvents(nrofPreload); + this.nextEventIndex = 0; + } + + /** + * Returns next event's time or Double.MAX_VALUE if there are no + * events left + * @return Next event's time + */ + public double nextEventsTime() { + if (eventsLeftInBuffer() <= 0 ) { + // in case user request time of an event that doesn't exist + return Double.MAX_VALUE; + } + else { + return queue.get(nextEventIndex).getTime(); + } + } + + /** + * Returns the next event in the queue or ExternalEvent with time of + * double.MAX_VALUE if there are no events left + * @return The next event + */ + public ExternalEvent nextEvent() { + if (queue.size() == 0) { // no more events + return new ExternalEvent(Double.MAX_VALUE); + } + + ExternalEvent ee = queue.get(nextEventIndex); + nextEventIndex++; + + if (nextEventIndex >= queue.size()) { // ran out of events + queue = readEvents(nrofPreload); + nextEventIndex = 0; + } + + return ee; + } + + /** + * Returns the amount of events left in the buffer at the moment + * (the amount can increase later if more events are read). + * @return The amount of events left or 0 there aren't any events + */ + public int eventsLeftInBuffer() { + if (queue == null || queue.size() == 0) { + return 0; + } + else { + return this.queue.size() - this.nextEventIndex; + } + } + + + /** + * Read some events from the external events reader + * @param nrof Maximum number of events to read + * @return A List of events that were read or an empty list if no events + * could be read + */ + private List readEvents(int nrof) { + if (allEventsRead) { + return new ArrayList(0); + } + + List events = reader.readEvents(nrof); + + if (nrof > 0 && events.size() == 0) { + reader.close(); + allEventsRead = true; + } + + return events; + } + +} diff --git a/input/ExternalEventsReader.java b/input/ExternalEventsReader.java index 01fc065df..b010617c1 100644 --- a/input/ExternalEventsReader.java +++ b/input/ExternalEventsReader.java @@ -1,27 +1,27 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - +package input; + import java.util.List; - -/** - * Interface for external event readers. - */ -public interface ExternalEventsReader { - - /** - * Read events from the reader - * @param nrof Maximum number of events to read - * @return Events in a List - */ - public List readEvents(int nrof); - - /** - * Closes the input file streams of the reader. - */ - public void close(); - - -} + +/** + * Interface for external event readers. + */ +public interface ExternalEventsReader { + + /** + * Read events from the reader + * @param nrof Maximum number of events to read + * @return Events in a List + */ + public List readEvents(int nrof); + + /** + * Closes the input file streams of the reader. + */ + public void close(); + + +} diff --git a/input/ExternalMovementReader.java b/input/ExternalMovementReader.java index 1ef7a480f..89ae9aaaf 100644 --- a/input/ExternalMovementReader.java +++ b/input/ExternalMovementReader.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - +package input; + import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; @@ -14,203 +14,203 @@ import core.Coord; import core.SettingsError; - - -/** - * Reader for ExternalMovement movement model's time-location tuples. - *

- * First line of the file should be the offset header. Syntax of the header - * should be:
- * minTime maxTime minX maxX minY maxY minZ maxZ - *
- * Last two values (Z-axis) are ignored at the moment but can be present - * in the file. - *

- * Following lines' syntax should be:
- * time id xPos yPos
- * where time is the time when a node with id should - * be at location (xPos, yPos). - *

- *

- * All lines must be sorted by time. Sampling interval (time difference between - * two time instances) must be same for the whole file. - *

- */ + + +/** + * Reader for ExternalMovement movement model's time-location tuples. + *

+ * First line of the file should be the offset header. Syntax of the header + * should be:
+ * minTime maxTime minX maxX minY maxY minZ maxZ + *
+ * Last two values (Z-axis) are ignored at the moment but can be present + * in the file. + *

+ * Following lines' syntax should be:
+ * time id xPos yPos
+ * where time is the time when a node with id should + * be at location (xPos, yPos). + *

+ *

+ * All lines must be sorted by time. Sampling interval (time difference between + * two time instances) must be same for the whole file. + *

+ */ public class ExternalMovementReader { /* Prefix for comment lines (lines starting with this are ignored) */ - public static final String COMMENT_PREFIX = "#"; - private Scanner scanner; - private double lastTimeStamp = -1; - private String lastLine; - private double minTime; - private double maxTime; - private double minX; - private double maxX; - private double minY; - private double maxY; - private boolean normalize; - - - /** - * Constructor. Creates a new reader that reads the data from a file. - * @param inFilePath Path to the file where the data is read - * @throws SettingsError if the file wasn't found - */ - public ExternalMovementReader(String inFilePath) { - this.normalize = true; - File inFile = new File(inFilePath); - try { - scanner = new Scanner(inFile); - } catch (FileNotFoundException e) { - throw new SettingsError("Couldn't find external movement input " + - "file " + inFile); - } - - String offsets = scanner.nextLine(); - - try { - Scanner lineScan = new Scanner(offsets); - minTime = lineScan.nextDouble(); - maxTime = lineScan.nextDouble(); - minX = lineScan.nextDouble(); - maxX = lineScan.nextDouble(); - minY = lineScan.nextDouble(); - maxY = lineScan.nextDouble(); - } catch (Exception e) { - throw new SettingsError("Invalid offset line '" + offsets + "'"); - } - - lastLine = scanner.nextLine(); - } - - /** - * Sets normalizing of read values on/off. If on, values returned by - * {@link #readNextMovements()} are decremented by minimum values of the - * offsets. Default is on (normalize). - * @param normalize If true, normalizing is on (false -> off). - */ - public void setNormalize(boolean normalize) { - this.normalize = normalize; - } - - /** - * Reads all new id-coordinate tuples that belong to the same time instance - * @return A list of tuples or empty list if there were no more moves - * @throws SettingError if an invalid line was read - */ - public List> readNextMovements() { - ArrayList> moves = - new ArrayList>(); - - if (!scanner.hasNextLine()) { - return moves; - } - - Scanner lineScan = new Scanner(lastLine); - double time = lineScan.nextDouble(); - String id = lineScan.next(); - double x = lineScan.nextDouble(); - double y = lineScan.nextDouble(); - - if (normalize) { - time -= minTime; - x -= minX; - y -= minY; - } - - lastTimeStamp = time; - - while (scanner.hasNextLine() && lastTimeStamp == time) { - lastLine = scanner.nextLine(); - - if (lastLine.trim().length() == 0 || - lastLine.startsWith(COMMENT_PREFIX)) { - continue; /* skip empty and comment lines */ + public static final String COMMENT_PREFIX = "#"; + private Scanner scanner; + private double lastTimeStamp = -1; + private String lastLine; + private double minTime; + private double maxTime; + private double minX; + private double maxX; + private double minY; + private double maxY; + private boolean normalize; + + + /** + * Constructor. Creates a new reader that reads the data from a file. + * @param inFilePath Path to the file where the data is read + * @throws SettingsError if the file wasn't found + */ + public ExternalMovementReader(String inFilePath) { + this.normalize = true; + File inFile = new File(inFilePath); + try { + scanner = new Scanner(inFile); + } catch (FileNotFoundException e) { + throw new SettingsError("Couldn't find external movement input " + + "file " + inFile); + } + + String offsets = scanner.nextLine(); + + try { + Scanner lineScan = new Scanner(offsets); + minTime = lineScan.nextDouble(); + maxTime = lineScan.nextDouble(); + minX = lineScan.nextDouble(); + maxX = lineScan.nextDouble(); + minY = lineScan.nextDouble(); + maxY = lineScan.nextDouble(); + } catch (Exception e) { + throw new SettingsError("Invalid offset line '" + offsets + "'"); + } + + lastLine = scanner.nextLine(); + } + + /** + * Sets normalizing of read values on/off. If on, values returned by + * {@link #readNextMovements()} are decremented by minimum values of the + * offsets. Default is on (normalize). + * @param normalize If true, normalizing is on (false -> off). + */ + public void setNormalize(boolean normalize) { + this.normalize = normalize; + } + + /** + * Reads all new id-coordinate tuples that belong to the same time instance + * @return A list of tuples or empty list if there were no more moves + * @throws SettingError if an invalid line was read + */ + public List> readNextMovements() { + ArrayList> moves = + new ArrayList>(); + + if (!scanner.hasNextLine()) { + return moves; + } + + Scanner lineScan = new Scanner(lastLine); + double time = lineScan.nextDouble(); + String id = lineScan.next(); + double x = lineScan.nextDouble(); + double y = lineScan.nextDouble(); + + if (normalize) { + time -= minTime; + x -= minX; + y -= minY; + } + + lastTimeStamp = time; + + while (scanner.hasNextLine() && lastTimeStamp == time) { + lastLine = scanner.nextLine(); + + if (lastLine.trim().length() == 0 || + lastLine.startsWith(COMMENT_PREFIX)) { + continue; /* skip empty and comment lines */ } - - // add previous line's tuple - moves.add(new Tuple(id, new Coord(x,y))); - - lineScan = new Scanner(lastLine); - - try { - time = lineScan.nextDouble(); - id = lineScan.next(); - x = lineScan.nextDouble(); - y = lineScan.nextDouble(); - } catch (Exception e) { - throw new SettingsError("Invalid line '" + lastLine + "'"); - } - - if (normalize) { - time -= minTime; - x -= minX; - y -= minY; - } - } - - if (!scanner.hasNextLine()) { // add the last tuple of the file - moves.add(new Tuple(id, new Coord(x,y))); - } - - return moves; - } - - /** - * Returns the time stamp where the last moves read with - * {@link #readNextMovements()} belong to. - * @return The time stamp - */ - public double getLastTimeStamp() { - return lastTimeStamp; - } - - /** - * Returns offset maxTime - * @return the maxTime - */ - public double getMaxTime() { - return maxTime; - } - - /** - * Returns offset maxX - * @return the maxX - */ - public double getMaxX() { - return maxX; - } - - /** - * Returns offset maxY - * @return the maxY - */ - public double getMaxY() { - return maxY; - } - - /** - * Returns offset minTime - * @return the minTime - */ - public double getMinTime() { - return minTime; - } - - /** - * Returns offset minX - * @return the minX - */ - public double getMinX() { - return minX; - } - - /** - * Returns offset minY - * @return the minY - */ - public double getMinY() { - return minY; - } - -} + + // add previous line's tuple + moves.add(new Tuple(id, new Coord(x,y))); + + lineScan = new Scanner(lastLine); + + try { + time = lineScan.nextDouble(); + id = lineScan.next(); + x = lineScan.nextDouble(); + y = lineScan.nextDouble(); + } catch (Exception e) { + throw new SettingsError("Invalid line '" + lastLine + "'"); + } + + if (normalize) { + time -= minTime; + x -= minX; + y -= minY; + } + } + + if (!scanner.hasNextLine()) { // add the last tuple of the file + moves.add(new Tuple(id, new Coord(x,y))); + } + + return moves; + } + + /** + * Returns the time stamp where the last moves read with + * {@link #readNextMovements()} belong to. + * @return The time stamp + */ + public double getLastTimeStamp() { + return lastTimeStamp; + } + + /** + * Returns offset maxTime + * @return the maxTime + */ + public double getMaxTime() { + return maxTime; + } + + /** + * Returns offset maxX + * @return the maxX + */ + public double getMaxX() { + return maxX; + } + + /** + * Returns offset maxY + * @return the maxY + */ + public double getMaxY() { + return maxY; + } + + /** + * Returns offset minTime + * @return the minTime + */ + public double getMinTime() { + return minTime; + } + + /** + * Returns offset minX + * @return the minX + */ + public double getMinX() { + return minX; + } + + /** + * Returns offset minY + * @return the minY + */ + public double getMinY() { + return minY; + } + +} diff --git a/input/ExternalPathMovementReader.java b/input/ExternalPathMovementReader.java index b49d95628..1a4085f50 100644 --- a/input/ExternalPathMovementReader.java +++ b/input/ExternalPathMovementReader.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package input; @@ -23,41 +23,41 @@ import core.SettingsError; -/** +/** *

External movement reader for traces that are in path format. Uses two * trace files, one for the paths and one for specifying activity times. * Nodes will follow the paths in the trace file, and pause between paths. * Activity times refer to the periods of time when there is valid trace data * about the node.

- * + * *

Reads external traces that are of the form:

* id time_1,x_1,y_1 time_2,x_2,y_2 ... \n - * + * *

The first line should be: * maxID minTime maxTime minX maxX minY maxY - * + * *

Activity trace file format is:

* id activeStart activeEnd\n - * + * *

* The ID in the trace files must match IDs of nodes in the simulation, the * coordinates must match the ONE coordinate system (units in meters) and the * times must match the ONE simulation time. *

- * + * *

Trace and activity files ending in .zip are assumed to be * compressed and will be automatically uncompressed during reading. The whole * trace is loaded into memory at once.

- * + * * @author teemuk * */ public class ExternalPathMovementReader { // Singletons are evil, but I'm lazy - private static Map singletons = + private static Map singletons = new HashMap(); - - /** + + /** * Represents a point on the path. */ public class Entry { @@ -65,20 +65,20 @@ public class Entry { public double x; public double y; } - - /** + + /** * Describes a node's activity time */ public class ActiveTime { public double start; public double end; } - + // Path cache private List>> paths = null; // Activity cache private List> activeTimes = null; - + // Settings private boolean normalize = true; private double minTime; @@ -88,11 +88,11 @@ public class ActiveTime { private double minY; private double maxY; private int maxID; - - /** + + /** * Creates a new reader by parsing the given files and building the internal * caches. - * + * * @param traceFilePath path to the trace file * @param activityFilePath path to the activity file */ @@ -104,7 +104,7 @@ private ExternalPathMovementReader(String traceFilePath, long totalRead = 0; long readSize = 0; long printSize = 5*1024*1024; - + BufferedReader reader = null; try { if (traceFilePath.endsWith(".zip")) { @@ -123,7 +123,7 @@ private ExternalPathMovementReader(String traceFilePath, throw new SettingsError("Couldn't find external movement input " + "file " + inFile); } - + /*Scanner scanner = null; try { scanner = new Scanner(inFile); @@ -131,7 +131,7 @@ private ExternalPathMovementReader(String traceFilePath, throw new SettingsError("Couldn't find external movement input " + "file " + inFile); }*/ - + // Parse header String offsets = reader.readLine(); if (offsets == null) { @@ -150,17 +150,17 @@ private ExternalPathMovementReader(String traceFilePath, } catch (Exception e) { throw new SettingsError("Invalid offset line '" + offsets + "'"); } - + // Initialize path cache this.paths = new ArrayList>>(this.maxID + 1); for (int i=0; i<=this.maxID; i++) { this.paths.add(i, new LinkedList>()); } - + // Parse traces String line = reader.readLine(); while (line != null) { - + readSize += line.length() + 1; if (readSize >= printSize) { totalRead += readSize; @@ -169,7 +169,7 @@ private ExternalPathMovementReader(String traceFilePath, " of " + (traceSize/1024) + "KB (" + Math.round(100.0*totalRead/traceSize) + "%)"); } - + if (line.equals("")) { line = reader.readLine(); continue; // Skip empty lines @@ -182,25 +182,25 @@ private ExternalPathMovementReader(String traceFilePath, String dataPoint = traceScan.next(); int d1 = dataPoint.indexOf(','); int d2 = dataPoint.indexOf(',', d1+1); - + Entry e = new Entry(); e.time = Double.parseDouble(dataPoint.substring(0, d1)); e.x = Double.parseDouble(dataPoint.substring(d1+1, d2)); e.y = Double.parseDouble(dataPoint.substring(d2+1)); - + if (this.normalize) { e.time -= this.minTime; e.x -= this.minX; e.y -= this.minY; } - + path.add(e); } paths.add(path); - + line = reader.readLine(); } - + // Parse activity times inFile = new File(activityFilePath); reader = null; @@ -220,13 +220,13 @@ private ExternalPathMovementReader(String traceFilePath, throw new SettingsError("Couldn't find external activity input " + "file " + inFile); } - + // Init activity cache this.activeTimes = new ArrayList>(this.maxID + 1); for (int i=0; i<=this.maxID; i++) { this.activeTimes.add(new LinkedList()); } - + // Parse the file line = reader.readLine(); while (line != null) { @@ -243,33 +243,33 @@ private ExternalPathMovementReader(String traceFilePath, a.end -= this.minTime; } times.add(a); - + line = reader.readLine(); } } - - /** + + /** * Returns the path for the node with the given ID. - * + * * @param ID ID of the node * @return full path for the node. */ public List> getPaths(int ID) { return this.paths.get(ID); } - - /** + + /** * Returns the active time for the given ID. - * + * * @param ID ID of the node * @return active times for the node. */ public List getActive(int ID) { return this.activeTimes.get(ID); } - + /** - * Sets normalizing of read values on/off. If on, values returned by + * Sets normalizing of read values on/off. If on, values returned by * {@link #readNextMovements()} are decremented by minimum values of the * offsets. Default is on (normalize). * @param normalize If true, normalizing is on (false -> off). @@ -277,8 +277,8 @@ public List getActive(int ID) { public void setNormalize(boolean normalize) { this.normalize = normalize; } - - + + /** * Returns offset maxTime * @return the maxTime @@ -326,13 +326,13 @@ public double getMinX() { public double getMinY() { return minY; } - - - /** + + + /** * Get an instance of the reader for the given file path. If the file has * already been read previously it will not be read again and instead the * previous instance of the reader will be returned. - * + * * @param filePath path where the file is read from * @return instance of the reader that has loaded all the paths from the * given trace file. @@ -342,7 +342,7 @@ public static ExternalPathMovementReader getInstance(String traceFilePath, if (!ExternalPathMovementReader.singletons.containsKey(traceFilePath)) { try { ExternalPathMovementReader.singletons.put(traceFilePath, - new ExternalPathMovementReader(traceFilePath, + new ExternalPathMovementReader(traceFilePath, activeFilePath)); } catch (IOException e) { System.exit(1); diff --git a/input/MessageBurstGenerator.java b/input/MessageBurstGenerator.java index 1dcb0b11e..ae950f429 100644 --- a/input/MessageBurstGenerator.java +++ b/input/MessageBurstGenerator.java @@ -1,92 +1,92 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package input; - -import core.Settings; - -/** - * Message creation -external events generator. Creates bursts of messages where - * every source node (defined with {@link MessageEventGenerator#HOST_RANGE_S}) - * creates a new message to every destination node (defined with - * {@link MessageEventGenerator#TO_HOST_RANGE_S})on every interval. - * The message size, burst times, and inter-burst intervals can be configured - * like with {@link MessageEventGenerator}. - * @see MessageEventGenerator - */ -public class MessageBurstGenerator extends MessageEventGenerator { - /** next index to use from the "from" range */ - private int nextFromOffset; - private int nextToOffset; - - public MessageBurstGenerator(Settings s) { - super(s); - this.nextFromOffset = 0; - this.nextToOffset = 0; - - if (this.toHostRange == null) { - this.toHostRange = this.hostRange; - } - } - - /** - * Returns the next message creation event - * @see input.EventQueue#nextEvent() - */ - public ExternalEvent nextEvent() { - int responseSize = 0; /* no responses requested */ - int msgSize; - int interval; - int from; - int to; - boolean nextBurst = false; - - from = this.hostRange[0] + nextFromOffset; - to = this.toHostRange[0] + nextToOffset; - - if (to == from) { /* skip self */ - to = this.toHostRange[0] + (++nextToOffset); - } - - msgSize = drawMessageSize(); - MessageCreateEvent mce = new MessageCreateEvent(from, to, getID(), - msgSize, responseSize, this.nextEventsTime); - - if (to < this.toHostRange[1] - 1) { - this.nextToOffset++; - } else { - if (from < this.hostRange[1] - 1) { - this.nextFromOffset++; - this.nextToOffset = 0; - } else { - nextBurst = true; - } - } - - if (this.hostRange[0] + nextFromOffset == - this.toHostRange[0] + nextToOffset) { - /* to and from would be same for next event */ - nextToOffset++; - if (nextToOffset >= toHostRange[1]) { - /* TODO: doesn't work correctly with non-aligned ranges */ - nextBurst = true; - } - } - - if (nextBurst) { - interval = drawNextEventTimeDiff(); - this.nextEventsTime += interval; - this.nextFromOffset = 0; - this.nextToOffset = 0; - } - - if (this.msgTime != null && this.nextEventsTime > this.msgTime[1]) { - /* next event would be later than the end time */ - this.nextEventsTime = Double.MAX_VALUE; - } - - return mce; - } - -} \ No newline at end of file + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import core.Settings; + +/** + * Message creation -external events generator. Creates bursts of messages where + * every source node (defined with {@link MessageEventGenerator#HOST_RANGE_S}) + * creates a new message to every destination node (defined with + * {@link MessageEventGenerator#TO_HOST_RANGE_S})on every interval. + * The message size, burst times, and inter-burst intervals can be configured + * like with {@link MessageEventGenerator}. + * @see MessageEventGenerator + */ +public class MessageBurstGenerator extends MessageEventGenerator { + /** next index to use from the "from" range */ + private int nextFromOffset; + private int nextToOffset; + + public MessageBurstGenerator(Settings s) { + super(s); + this.nextFromOffset = 0; + this.nextToOffset = 0; + + if (this.toHostRange == null) { + this.toHostRange = this.hostRange; + } + } + + /** + * Returns the next message creation event + * @see input.EventQueue#nextEvent() + */ + public ExternalEvent nextEvent() { + int responseSize = 0; /* no responses requested */ + int msgSize; + int interval; + int from; + int to; + boolean nextBurst = false; + + from = this.hostRange[0] + nextFromOffset; + to = this.toHostRange[0] + nextToOffset; + + if (to == from) { /* skip self */ + to = this.toHostRange[0] + (++nextToOffset); + } + + msgSize = drawMessageSize(); + MessageCreateEvent mce = new MessageCreateEvent(from, to, getID(), + msgSize, responseSize, this.nextEventsTime); + + if (to < this.toHostRange[1] - 1) { + this.nextToOffset++; + } else { + if (from < this.hostRange[1] - 1) { + this.nextFromOffset++; + this.nextToOffset = 0; + } else { + nextBurst = true; + } + } + + if (this.hostRange[0] + nextFromOffset == + this.toHostRange[0] + nextToOffset) { + /* to and from would be same for next event */ + nextToOffset++; + if (nextToOffset >= toHostRange[1]) { + /* TODO: doesn't work correctly with non-aligned ranges */ + nextBurst = true; + } + } + + if (nextBurst) { + interval = drawNextEventTimeDiff(); + this.nextEventsTime += interval; + this.nextFromOffset = 0; + this.nextToOffset = 0; + } + + if (this.msgTime != null && this.nextEventsTime > this.msgTime[1]) { + /* next event would be later than the end time */ + this.nextEventsTime = Double.MAX_VALUE; + } + + return mce; + } + +} diff --git a/input/MessageCreateEvent.java b/input/MessageCreateEvent.java index 27d8f0236..1f13c9b26 100644 --- a/input/MessageCreateEvent.java +++ b/input/MessageCreateEvent.java @@ -1,54 +1,54 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package input; - -import core.DTNHost; -import core.Message; -import core.World; - -/** - * External event for creating a message. - */ -public class MessageCreateEvent extends MessageEvent { - private int size; - private int responseSize; - - /** - * Creates a message creation event with a optional response request - * @param from The creator of the message - * @param to Where the message is destined to - * @param id ID of the message - * @param size Size of the message - * @param responseSize Size of the requested response message or 0 if - * no response is requested - * @param time Time, when the message is created - */ - public MessageCreateEvent(int from, int to, String id, int size, - int responseSize, double time) { - super(from,to, id, time); - this.size = size; - this.responseSize = responseSize; - } - - - /** - * Creates the message this event represents. - */ - @Override - public void processEvent(World world) { - DTNHost to = world.getNodeByAddress(this.toAddr); - DTNHost from = world.getNodeByAddress(this.fromAddr); - - Message m = new Message(from, to, this.id, this.size); - m.setResponseSize(this.responseSize); - from.createNewMessage(m); - } - - @Override - public String toString() { - return super.toString() + " [" + fromAddr + "->" + toAddr + "] " + - "size:" + size + " CREATE"; - } -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import core.DTNHost; +import core.Message; +import core.World; + +/** + * External event for creating a message. + */ +public class MessageCreateEvent extends MessageEvent { + private int size; + private int responseSize; + + /** + * Creates a message creation event with a optional response request + * @param from The creator of the message + * @param to Where the message is destined to + * @param id ID of the message + * @param size Size of the message + * @param responseSize Size of the requested response message or 0 if + * no response is requested + * @param time Time, when the message is created + */ + public MessageCreateEvent(int from, int to, String id, int size, + int responseSize, double time) { + super(from,to, id, time); + this.size = size; + this.responseSize = responseSize; + } + + + /** + * Creates the message this event represents. + */ + @Override + public void processEvent(World world) { + DTNHost to = world.getNodeByAddress(this.toAddr); + DTNHost from = world.getNodeByAddress(this.fromAddr); + + Message m = new Message(from, to, this.id, this.size); + m.setResponseSize(this.responseSize); + from.createNewMessage(m); + } + + @Override + public String toString() { + return super.toString() + " [" + fromAddr + "->" + toAddr + "] " + + "size:" + size + " CREATE"; + } +} diff --git a/input/MessageDeleteEvent.java b/input/MessageDeleteEvent.java index b29671779..991b0bdf5 100644 --- a/input/MessageDeleteEvent.java +++ b/input/MessageDeleteEvent.java @@ -1,43 +1,43 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - +package input; + import java.util.ArrayList; import java.util.List; -import core.DTNHost; +import core.DTNHost; import core.Message; -import core.World; - -/** - * External event for deleting a message. - */ - -public class MessageDeleteEvent extends MessageEvent { - /** is the delete caused by a drop (not "normal" removing) */ - private boolean drop; - - /** - * Creates a message delete event - * @param host Where to delete the message - * @param id ID of the message - * @param time Time when the message is deleted - */ - public MessageDeleteEvent(int host, String id, double time, - boolean drop) { - super(host, host, id, time); - this.drop = drop; - } - - /** - * Deletes the message +import core.World; + +/** + * External event for deleting a message. + */ + +public class MessageDeleteEvent extends MessageEvent { + /** is the delete caused by a drop (not "normal" removing) */ + private boolean drop; + + /** + * Creates a message delete event + * @param host Where to delete the message + * @param id ID of the message + * @param time Time when the message is deleted */ - @Override - public void processEvent(World world) { + public MessageDeleteEvent(int host, String id, double time, + boolean drop) { + super(host, host, id, time); + this.drop = drop; + } + + /** + * Deletes the message + */ + @Override + public void processEvent(World world) { DTNHost host = world.getNodeByAddress(this.fromAddr); - + if (id.equals(StandardEventsReader.ALL_MESSAGES_ID)) { List ids = new ArrayList(); for (Message m : host.getMessageCollection()) { @@ -46,14 +46,14 @@ public void processEvent(World world) { for (String nextId : ids) { host.deleteMessage(nextId, drop); } - } else { + } else { host.deleteMessage(id, drop); - } - } - - @Override - public String toString() { - return super.toString() + " [" + fromAddr + "] DELETE"; - } - -} + } + } + + @Override + public String toString() { + return super.toString() + " [" + fromAddr + "] DELETE"; + } + +} diff --git a/input/MessageEvent.java b/input/MessageEvent.java index fb267b143..28cb34caf 100644 --- a/input/MessageEvent.java +++ b/input/MessageEvent.java @@ -1,36 +1,36 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - -/** - * A message related external event - */ -public abstract class MessageEvent extends ExternalEvent { - /** address of the node the message is from */ - protected int fromAddr; - /** address of the node the message is to */ - protected int toAddr; - /** identifier of the message */ - protected String id; - - /** - * Creates a message event - * @param from Where the message comes from - * @param to Who the message goes to - * @param id ID of the message - * @param time Time when the message event occurs - */ - public MessageEvent(int from, int to, String id, double time) { - super(time); - this.fromAddr = from; - this.toAddr= to; - this.id = id; - } - - @Override - public String toString() { - return "MSG @" + this.time + " " + id; - } -} +package input; + +/** + * A message related external event + */ +public abstract class MessageEvent extends ExternalEvent { + /** address of the node the message is from */ + protected int fromAddr; + /** address of the node the message is to */ + protected int toAddr; + /** identifier of the message */ + protected String id; + + /** + * Creates a message event + * @param from Where the message comes from + * @param to Who the message goes to + * @param id ID of the message + * @param time Time when the message event occurs + */ + public MessageEvent(int from, int to, String id, double time) { + super(time); + this.fromAddr = from; + this.toAddr= to; + this.id = id; + } + + @Override + public String toString() { + return "MSG @" + this.time + " " + id; + } +} diff --git a/input/MessageEventGenerator.java b/input/MessageEventGenerator.java index 1c9aa45bd..bf2c87c67 100644 --- a/input/MessageEventGenerator.java +++ b/input/MessageEventGenerator.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package input; @@ -19,21 +19,21 @@ public class MessageEventGenerator implements EventQueue { * value or a range (min, max) of uniformly distributed random values. * Defines the message size (bytes). */ public static final String MESSAGE_SIZE_S = "size"; - /** Message creation interval range -setting id ({@value}). Can be either a - * single value or a range (min, max) of uniformly distributed + /** Message creation interval range -setting id ({@value}). Can be either a + * single value or a range (min, max) of uniformly distributed * random values. Defines the inter-message creation interval (seconds). */ public static final String MESSAGE_INTERVAL_S = "interval"; - /** Sender/receiver address range -setting id ({@value}). + /** Sender/receiver address range -setting id ({@value}). * The lower bound is inclusive and upper bound exclusive. */ public static final String HOST_RANGE_S = "hosts"; - /** (Optional) receiver address range -setting id ({@value}). - * If a value for this setting is defined, the destination hosts are - * selected from this range and the source hosts from the - * {@link #HOST_RANGE_S} setting's range. + /** (Optional) receiver address range -setting id ({@value}). + * If a value for this setting is defined, the destination hosts are + * selected from this range and the source hosts from the + * {@link #HOST_RANGE_S} setting's range. * The lower bound is inclusive and upper bound exclusive. */ public static final String TO_HOST_RANGE_S = "tohosts"; - /** Message ID prefix -setting id ({@value}). The value must be unique + /** Message ID prefix -setting id ({@value}). The value must be unique * for all message sources, so if you have more than one message generator, * use different prefix for all of them. The random number generator's * seed is derived from the prefix, so by changing the prefix, you'll get @@ -41,10 +41,10 @@ public class MessageEventGenerator implements EventQueue { public static final String MESSAGE_ID_PREFIX_S = "prefix"; /** Message creation time range -setting id ({@value}). Defines the time * range when messages are created. No messages are created before the first - * and after the second value. By default, messages are created for the + * and after the second value. By default, messages are created for the * whole simulation time. */ public static final String MESSAGE_TIME_S = "time"; - + /** Time of the next event (simulated seconds) */ protected double nextEventsTime = 0; /** Range of host addresses that can be senders or receivers */ @@ -64,10 +64,10 @@ public class MessageEventGenerator implements EventQueue { /** Random number generator for this Class */ protected Random rng; - + /** - * Constructor, initializes the interval between events, - * and the size of messages generated, as well as number + * Constructor, initializes the interval between events, + * and the size of messages generated, as well as number * of hosts in the network. * @param s Settings for this generator. */ @@ -76,7 +76,7 @@ public MessageEventGenerator(Settings s){ this.msgInterval = s.getCsvInts(MESSAGE_INTERVAL_S); this.hostRange = s.getCsvInts(HOST_RANGE_S, 2); this.idPrefix = s.getSetting(MESSAGE_ID_PREFIX_S); - + if (s.contains(MESSAGE_TIME_S)) { this.msgTime = s.getCsvDoubles(MESSAGE_TIME_S, 2); } @@ -89,10 +89,10 @@ public MessageEventGenerator(Settings s){ else { this.toHostRange = null; } - + /* if prefix is unique, so will be the rng's sequence */ this.rng = new Random(idPrefix.hashCode()); - + if (this.sizeRange.length == 1) { /* convert single value to range with 0 length */ this.sizeRange = new int[] {this.sizeRange[0], this.sizeRange[0]}; @@ -101,37 +101,37 @@ public MessageEventGenerator(Settings s){ s.assertValidRange(this.sizeRange, MESSAGE_SIZE_S); } if (this.msgInterval.length == 1) { - this.msgInterval = new int[] {this.msgInterval[0], + this.msgInterval = new int[] {this.msgInterval[0], this.msgInterval[0]}; } else { s.assertValidRange(this.msgInterval, MESSAGE_INTERVAL_S); } s.assertValidRange(this.hostRange, HOST_RANGE_S); - + if (this.hostRange[1] - this.hostRange[0] < 2) { if (this.toHostRange == null) { - throw new SettingsError("Host range must contain at least two " + throw new SettingsError("Host range must contain at least two " + "nodes unless toHostRange is defined"); } - else if (toHostRange[0] == this.hostRange[0] && + else if (toHostRange[0] == this.hostRange[0] && toHostRange[1] == this.hostRange[1]) { // XXX: teemuk: Since (X,X) == (X,X+1) in drawHostAddress() // there's still a boundary condition that can cause an // infinite loop. - throw new SettingsError("If to and from host ranges contain" + + throw new SettingsError("If to and from host ranges contain" + " only one host, they can't be the equal"); } } - + /* calculate the first event's time */ - this.nextEventsTime = (this.msgTime != null ? this.msgTime[0] : 0) - + msgInterval[0] + - (msgInterval[0] == msgInterval[1] ? 0 : + this.nextEventsTime = (this.msgTime != null ? this.msgTime[0] : 0) + + msgInterval[0] + + (msgInterval[0] == msgInterval[1] ? 0 : rng.nextInt(msgInterval[1] - msgInterval[0])); } - - + + /** * Draws a random host address from the configured address range * @param hostRange The range of hosts @@ -143,27 +143,27 @@ protected int drawHostAddress(int hostRange[]) { } return hostRange[0] + rng.nextInt(hostRange[1] - hostRange[0]); } - + /** * Generates a (random) message size * @return message size */ protected int drawMessageSize() { - int sizeDiff = sizeRange[0] == sizeRange[1] ? 0 : + int sizeDiff = sizeRange[0] == sizeRange[1] ? 0 : rng.nextInt(sizeRange[1] - sizeRange[0]); return sizeRange[0] + sizeDiff; } - + /** * Generates a (random) time difference between two events * @return the time difference */ protected int drawNextEventTimeDiff() { - int timeDiff = msgInterval[0] == msgInterval[1] ? 0 : + int timeDiff = msgInterval[0] == msgInterval[1] ? 0 : rng.nextInt(msgInterval[1] - msgInterval[0]); return msgInterval[0] + timeDiff; } - + /** * Draws a destination host address that is different from the "from" * address @@ -175,13 +175,13 @@ protected int drawToAddress(int hostRange[], int from) { int to; do { to = this.toHostRange != null ? drawHostAddress(this.toHostRange): - drawHostAddress(this.hostRange); + drawHostAddress(this.hostRange); } while (from==to); - + return to; } - - /** + + /** * Returns the next message creation event * @see input.EventQueue#nextEvent() */ @@ -191,24 +191,24 @@ public ExternalEvent nextEvent() { int interval; int from; int to; - + /* Get two *different* nodes randomly from the host ranges */ - from = drawHostAddress(this.hostRange); + from = drawHostAddress(this.hostRange); to = drawToAddress(hostRange, from); - + msgSize = drawMessageSize(); interval = drawNextEventTimeDiff(); - + /* Create event and advance to next event */ - MessageCreateEvent mce = new MessageCreateEvent(from, to, this.getID(), + MessageCreateEvent mce = new MessageCreateEvent(from, to, this.getID(), msgSize, responseSize, this.nextEventsTime); - this.nextEventsTime += interval; - + this.nextEventsTime += interval; + if (this.msgTime != null && this.nextEventsTime > this.msgTime[1]) { /* next event would be later than the end time */ this.nextEventsTime = Double.MAX_VALUE; } - + return mce; } @@ -219,7 +219,7 @@ public ExternalEvent nextEvent() { public double nextEventsTime() { return this.nextEventsTime; } - + /** * Returns a next free message ID * @return next globally unique message ID @@ -227,5 +227,5 @@ public double nextEventsTime() { protected String getID(){ this.id++; return idPrefix + this.id; - } + } } diff --git a/input/MessageRelayEvent.java b/input/MessageRelayEvent.java index 4d9d43199..e075a100f 100644 --- a/input/MessageRelayEvent.java +++ b/input/MessageRelayEvent.java @@ -1,70 +1,70 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - +package input; + import core.DTNHost; import core.World; - -/** - * External event for all the stages of relaying a message between two - * hosts (start and possible abort or delivery). - */ -public class MessageRelayEvent extends MessageEvent { - private int stage; - - /** Message relay stage constant for start of sending */ - public static final int SENDING = 1; - /** Message relay stage constant for ready delivery */ - public static final int TRANSFERRED = 2; - /** Message relay stage constant for aborted delivery */ - public static final int ABORTED = 3; - /** Stage constant -> String representation mapping */ - public static final String[] STAGE_STRINGS = {"SENDING", - "TRANSFERRED", "ABORTED"}; - - /** - * Creates a message relaying event - * @param from Where the message comes from (at this hop) - * @param to Who the message goes to (at this hop) - * @param id ID of the message - * @param time Time when this event happens - * @param stage The stage of the event (SENDING, TRANSFERRED, or ABORTED) - */ - public MessageRelayEvent(int from, int to, String id, double time, - int stage) { - super(from, to, id, time); - this.stage = stage; - } - - /** - * Relays the message - */ - public void processEvent(World world) { - // get DTNHosts and pass messages between them - DTNHost from = world.getNodeByAddress(this.fromAddr); - DTNHost to = world.getNodeByAddress(this.toAddr); - - switch(stage) { - case SENDING: - from.sendMessage(id, to); - break; - case TRANSFERRED: - to.messageTransferred(id, from); - break; - case ABORTED: - to.messageAborted(id, from, -1); - break; - default: - assert false : "Invalid stage (" + stage + ") for " + this; - } - } - - @Override - public String toString() { - return super.toString() + " [" + fromAddr + "->" + toAddr + "] " + - STAGE_STRINGS[stage-1]; - } - -} + +/** + * External event for all the stages of relaying a message between two + * hosts (start and possible abort or delivery). + */ +public class MessageRelayEvent extends MessageEvent { + private int stage; + + /** Message relay stage constant for start of sending */ + public static final int SENDING = 1; + /** Message relay stage constant for ready delivery */ + public static final int TRANSFERRED = 2; + /** Message relay stage constant for aborted delivery */ + public static final int ABORTED = 3; + /** Stage constant -> String representation mapping */ + public static final String[] STAGE_STRINGS = {"SENDING", + "TRANSFERRED", "ABORTED"}; + + /** + * Creates a message relaying event + * @param from Where the message comes from (at this hop) + * @param to Who the message goes to (at this hop) + * @param id ID of the message + * @param time Time when this event happens + * @param stage The stage of the event (SENDING, TRANSFERRED, or ABORTED) + */ + public MessageRelayEvent(int from, int to, String id, double time, + int stage) { + super(from, to, id, time); + this.stage = stage; + } + + /** + * Relays the message + */ + public void processEvent(World world) { + // get DTNHosts and pass messages between them + DTNHost from = world.getNodeByAddress(this.fromAddr); + DTNHost to = world.getNodeByAddress(this.toAddr); + + switch(stage) { + case SENDING: + from.sendMessage(id, to); + break; + case TRANSFERRED: + to.messageTransferred(id, from); + break; + case ABORTED: + to.messageAborted(id, from, -1); + break; + default: + assert false : "Invalid stage (" + stage + ") for " + this; + } + } + + @Override + public String toString() { + return super.toString() + " [" + fromAddr + "->" + toAddr + "] " + + STAGE_STRINGS[stage-1]; + } + +} diff --git a/input/OneFromEachMessageGenerator.java b/input/OneFromEachMessageGenerator.java index b30399819..793752c2f 100644 --- a/input/OneFromEachMessageGenerator.java +++ b/input/OneFromEachMessageGenerator.java @@ -1,75 +1,75 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package input; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import core.Settings; -import core.SettingsError; - -/** - * Message creation -external events generator. Creates one message from - * every source node (defined with {@link MessageEventGenerator#HOST_RANGE_S}) - * to one of the destination nodes (defined with - * {@link MessageEventGenerator#TO_HOST_RANGE_S}). - * The message size, first messages time and the intervals between creating - * messages can be configured like with {@link MessageEventGenerator}. End - * time is not respected, but messages are created until every from-node has - * created a message. - * @see MessageEventGenerator - */ -public class OneFromEachMessageGenerator extends MessageEventGenerator { - private List fromIds; - - public OneFromEachMessageGenerator(Settings s) { - super(s); - this.fromIds = new ArrayList(); - - if (toHostRange == null) { - throw new SettingsError("Destination host (" + TO_HOST_RANGE_S + - ") must be defined"); - } - for (int i = hostRange[0]; i < hostRange[1]; i++) { - fromIds.add(i); - } - Collections.shuffle(fromIds, rng); - } - - /** - * Returns the next message creation event - * @see input.EventQueue#nextEvent() - */ - public ExternalEvent nextEvent() { - int responseSize = 0; /* no responses requested */ - int from; - int to; - - from = this.fromIds.remove(0); - to = drawToAddress(toHostRange, -1); - - if (to == from) { /* skip self */ - if (this.fromIds.size() == 0) { /* oops, no more from addresses */ - this.nextEventsTime = Double.MAX_VALUE; - return new ExternalEvent(Double.MAX_VALUE); - } else { - from = this.fromIds.remove(0); - } - } - - if (this.fromIds.size() == 0) { - this.nextEventsTime = Double.MAX_VALUE; /* no messages left */ - } else { - this.nextEventsTime += drawNextEventTimeDiff(); - } - - MessageCreateEvent mce = new MessageCreateEvent(from, to, getID(), - drawMessageSize(), responseSize, this.nextEventsTime); - - return mce; - } - -} \ No newline at end of file + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import core.Settings; +import core.SettingsError; + +/** + * Message creation -external events generator. Creates one message from + * every source node (defined with {@link MessageEventGenerator#HOST_RANGE_S}) + * to one of the destination nodes (defined with + * {@link MessageEventGenerator#TO_HOST_RANGE_S}). + * The message size, first messages time and the intervals between creating + * messages can be configured like with {@link MessageEventGenerator}. End + * time is not respected, but messages are created until every from-node has + * created a message. + * @see MessageEventGenerator + */ +public class OneFromEachMessageGenerator extends MessageEventGenerator { + private List fromIds; + + public OneFromEachMessageGenerator(Settings s) { + super(s); + this.fromIds = new ArrayList(); + + if (toHostRange == null) { + throw new SettingsError("Destination host (" + TO_HOST_RANGE_S + + ") must be defined"); + } + for (int i = hostRange[0]; i < hostRange[1]; i++) { + fromIds.add(i); + } + Collections.shuffle(fromIds, rng); + } + + /** + * Returns the next message creation event + * @see input.EventQueue#nextEvent() + */ + public ExternalEvent nextEvent() { + int responseSize = 0; /* no responses requested */ + int from; + int to; + + from = this.fromIds.remove(0); + to = drawToAddress(toHostRange, -1); + + if (to == from) { /* skip self */ + if (this.fromIds.size() == 0) { /* oops, no more from addresses */ + this.nextEventsTime = Double.MAX_VALUE; + return new ExternalEvent(Double.MAX_VALUE); + } else { + from = this.fromIds.remove(0); + } + } + + if (this.fromIds.size() == 0) { + this.nextEventsTime = Double.MAX_VALUE; /* no messages left */ + } else { + this.nextEventsTime += drawNextEventTimeDiff(); + } + + MessageCreateEvent mce = new MessageCreateEvent(from, to, getID(), + drawMessageSize(), responseSize, this.nextEventsTime); + + return mce; + } + +} diff --git a/input/OneToEachMessageGenerator.java b/input/OneToEachMessageGenerator.java index 157fa27e5..d0294495b 100644 --- a/input/OneToEachMessageGenerator.java +++ b/input/OneToEachMessageGenerator.java @@ -1,75 +1,75 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package input; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import core.Settings; -import core.SettingsError; - -/** - * Message creation -external events generator. Creates one message from - * source node/nodes (defined with {@link MessageEventGenerator#HOST_RANGE_S}) - * to all destination nodes (defined with - * {@link MessageEventGenerator#TO_HOST_RANGE_S}). - * The message size, first messages time and the intervals between creating - * messages can be configured like with {@link MessageEventGenerator}. End - * time is not respected, but messages are created until there's a message for - * every destination node. - * @see MessageEventGenerator - */ -public class OneToEachMessageGenerator extends MessageEventGenerator { - private List toIds; - - public OneToEachMessageGenerator(Settings s) { - super(s); - this.toIds = new ArrayList(); - - if (toHostRange == null) { - throw new SettingsError("Destination host (" + TO_HOST_RANGE_S + - ") must be defined"); - } - for (int i = toHostRange[0]; i < toHostRange[1]; i++) { - toIds.add(i); - } - Collections.shuffle(toIds, rng); - } - - /** - * Returns the next message creation event - * @see input.EventQueue#nextEvent() - */ - public ExternalEvent nextEvent() { - int responseSize = 0; /* no responses requested */ - int from; - int to; - - from = drawHostAddress(hostRange); - to = this.toIds.remove(0); - - if (to == from) { /* skip self */ - if (this.toIds.size() == 0) { /* oops, no more from addresses */ - this.nextEventsTime = Double.MAX_VALUE; - return new ExternalEvent(Double.MAX_VALUE); - } else { - to = this.toIds.remove(0); - } - } - - if (this.toIds.size() == 0) { - this.nextEventsTime = Double.MAX_VALUE; /* no messages left */ - } else { - this.nextEventsTime += drawNextEventTimeDiff(); - } - - MessageCreateEvent mce = new MessageCreateEvent(from, to, getID(), - drawMessageSize(), responseSize, this.nextEventsTime); - - return mce; - } - -} \ No newline at end of file + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import core.Settings; +import core.SettingsError; + +/** + * Message creation -external events generator. Creates one message from + * source node/nodes (defined with {@link MessageEventGenerator#HOST_RANGE_S}) + * to all destination nodes (defined with + * {@link MessageEventGenerator#TO_HOST_RANGE_S}). + * The message size, first messages time and the intervals between creating + * messages can be configured like with {@link MessageEventGenerator}. End + * time is not respected, but messages are created until there's a message for + * every destination node. + * @see MessageEventGenerator + */ +public class OneToEachMessageGenerator extends MessageEventGenerator { + private List toIds; + + public OneToEachMessageGenerator(Settings s) { + super(s); + this.toIds = new ArrayList(); + + if (toHostRange == null) { + throw new SettingsError("Destination host (" + TO_HOST_RANGE_S + + ") must be defined"); + } + for (int i = toHostRange[0]; i < toHostRange[1]; i++) { + toIds.add(i); + } + Collections.shuffle(toIds, rng); + } + + /** + * Returns the next message creation event + * @see input.EventQueue#nextEvent() + */ + public ExternalEvent nextEvent() { + int responseSize = 0; /* no responses requested */ + int from; + int to; + + from = drawHostAddress(hostRange); + to = this.toIds.remove(0); + + if (to == from) { /* skip self */ + if (this.toIds.size() == 0) { /* oops, no more from addresses */ + this.nextEventsTime = Double.MAX_VALUE; + return new ExternalEvent(Double.MAX_VALUE); + } else { + to = this.toIds.remove(0); + } + } + + if (this.toIds.size() == 0) { + this.nextEventsTime = Double.MAX_VALUE; /* no messages left */ + } else { + this.nextEventsTime += drawNextEventTimeDiff(); + } + + MessageCreateEvent mce = new MessageCreateEvent(from, to, getID(), + drawMessageSize(), responseSize, this.nextEventsTime); + + return mce; + } + +} diff --git a/input/ScheduledUpdatesQueue.java b/input/ScheduledUpdatesQueue.java index b4b98f7a4..fa0259e82 100644 --- a/input/ScheduledUpdatesQueue.java +++ b/input/ScheduledUpdatesQueue.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package input; @@ -9,14 +9,14 @@ /** * Event queue where simulation objects can request an update to happen - * at the specified simulation time. Multiple updates at the same time + * at the specified simulation time. Multiple updates at the same time * are merged to a single update. */ public class ScheduledUpdatesQueue implements EventQueue { /** Time of the event (simulated seconds) */ private ExternalEvent nextEvent; private List updates; - + /** * Constructor. Creates an empty update queue. */ @@ -24,25 +24,25 @@ public ScheduledUpdatesQueue(){ this.nextEvent = new ExternalEvent(Double.MAX_VALUE); this.updates = new ArrayList(); } - + /** * Returns the next scheduled event or event with time Double.MAX_VALUE - * if there aren't any. + * if there aren't any. * @return the next scheduled event */ public ExternalEvent nextEvent() { ExternalEvent event = this.nextEvent; - + if (this.updates.size() == 0) { this.nextEvent = new ExternalEvent(Double.MAX_VALUE); } else { this.nextEvent = this.updates.remove(0); } - + return event; } - + /** * Returns the next scheduled event's time or Double.MAX_VALUE if there * aren't any events left @@ -70,14 +70,14 @@ else if (this.nextEvent.getTime() > simTime) { // new nextEvent putToQueue(ee); } } - + /** * Puts a event to the queue in the right place * @param ee The event to put to the queue */ private void putToQueue(ExternalEvent ee) { double eeTime = ee.getTime(); - + for (int i=0, n=this.updates.size(); i add to the end of the list */ - this.updates.add(ee); + this.updates.add(ee); } - + public String toString() { String times = "updates @ " + this.nextEvent.getTime(); - + for (ExternalEvent ee : this.updates) { times += ", " + ee.getTime(); } - + return times; } } diff --git a/input/StandardEventsReader.java b/input/StandardEventsReader.java index 7e09f661c..99b462c70 100644 --- a/input/StandardEventsReader.java +++ b/input/StandardEventsReader.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - +package input; + import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; @@ -15,45 +15,45 @@ import java.util.regex.Pattern; import core.SimError; - -/** - *

- * External events reader for standard-format events - * (created e.g by the dtnsim2parser). - *

- *

- * Syntax:
- * - * <time> <actionId> <msgId> <hostId> - * [<host2Id> [<size>] [<respSize>]] - * - *

- * All actions (except CONNECTION) must have first four fields. SEND, DELIVERED - * and ABORT actions need host2Id field too (the host who the message is/was - * being transferred to). CREATE action needs the additional size - * (of the message) field and can have also size-of-the-response field if + +/** + *

+ * External events reader for standard-format events + * (created e.g by the dtnsim2parser). + *

+ *

+ * Syntax:
+ * + * <time> <actionId> <msgId> <hostId> + * [<host2Id> [<size>] [<respSize>]] + * + *

+ * All actions (except CONNECTION) must have first four fields. SEND, DELIVERED + * and ABORT actions need host2Id field too (the host who the message is/was + * being transferred to). CREATE action needs the additional size + * (of the message) field and can have also size-of-the-response field if * a response to this message is requested.

- *

CONNNECTION action is followed by the two hosts which connect (or + *

CONNNECTION action is followed by the two hosts which connect (or * disconnect) to each other and then either "up" or "down" depending on whether - * the connection was created or destroyed. + * the connection was created or destroyed. *

*

Message DROP and REMOVE events can use {@value #ALL_MESSAGES_ID} as the - * message ID for referring to all messages the node has in message buffer + * message ID for referring to all messages the node has in message buffer * (i.e., to delete all messages). - *

- */ -public class StandardEventsReader implements ExternalEventsReader { - /** Identifier of message creation event ({@value}) */ - public static final String CREATE = "C"; - /** Identifier of message transfer start event ({@value}) */ - public static final String SEND = "S"; - /** Identifier of message delivered event ({@value}) */ - public static final String DELIVERED = "DE"; - /** Identifier of message transfer aborted event ({@value}) */ - public static final String ABORT = "A"; - /** Identifier of message dropped event ({@value}) */ - public static final String DROP = "DR"; - /** Identifier of message removed event ({@value}) */ + *

+ */ +public class StandardEventsReader implements ExternalEventsReader { + /** Identifier of message creation event ({@value}) */ + public static final String CREATE = "C"; + /** Identifier of message transfer start event ({@value}) */ + public static final String SEND = "S"; + /** Identifier of message delivered event ({@value}) */ + public static final String DELIVERED = "DE"; + /** Identifier of message transfer aborted event ({@value}) */ + public static final String ABORT = "A"; + /** Identifier of message dropped event ({@value}) */ + public static final String DROP = "DR"; + /** Identifier of message removed event ({@value}) */ public static final String REMOVE = "R"; /** Identifier of connection event ({@value}) */ public static final String CONNECTION = "CONN"; @@ -61,68 +61,68 @@ public class StandardEventsReader implements ExternalEventsReader { public static final String CONNECTION_DOWN = "down"; /** Value identifier of connection up event ({@value}) */ public static final String CONNECTION_UP = "up"; - /** Message identifier to use to refer to all messages ({@value}) */ - public static final String ALL_MESSAGES_ID = "*"; - + /** Message identifier to use to refer to all messages ({@value}) */ + public static final String ALL_MESSAGES_ID = "*"; + //private Scanner scanner; - private BufferedReader reader; - - public StandardEventsReader(File eventsFile){ - try { + private BufferedReader reader; + + public StandardEventsReader(File eventsFile){ + try { //this.scanner = new Scanner(eventsFile); - this.reader = new BufferedReader(new FileReader(eventsFile)); - } catch (FileNotFoundException e) { - throw new SimError(e.getMessage(),e); - } - } - - - public List readEvents(int nrof) { - ArrayList events = new ArrayList(nrof); - int eventsRead = 0; - // skip empty and comment lines - Pattern skipPattern = Pattern.compile("(#.*)|(^\\s*$)"); - + this.reader = new BufferedReader(new FileReader(eventsFile)); + } catch (FileNotFoundException e) { + throw new SimError(e.getMessage(),e); + } + } + + + public List readEvents(int nrof) { + ArrayList events = new ArrayList(nrof); + int eventsRead = 0; + // skip empty and comment lines + Pattern skipPattern = Pattern.compile("(#.*)|(^\\s*$)"); + String line; try { line = this.reader.readLine(); } catch (IOException e1) { throw new SimError("Reading from external event file failed."); - } - while (eventsRead < nrof && line != null) { - Scanner lineScan = new Scanner(line); - if (skipPattern.matcher(line).matches()) { + } + while (eventsRead < nrof && line != null) { + Scanner lineScan = new Scanner(line); + if (skipPattern.matcher(line).matches()) { // skip empty and comment lines try { line = this.reader.readLine(); } catch (IOException e) { throw new SimError("Reading from external event file " + "failed."); - } - continue; - } - - double time; - String action; - String msgId; - int hostAddr; + } + continue; + } + + double time; + String action; + String msgId; + int hostAddr; int host2Addr; - - try { - time = lineScan.nextDouble(); - action = lineScan.next(); - - if (action.equals(DROP)) { + + try { + time = lineScan.nextDouble(); + action = lineScan.next(); + + if (action.equals(DROP)) { msgId = lineScan.next(); hostAddr = getHostAddress(lineScan.next()); - events.add(new MessageDeleteEvent(hostAddr, msgId, - time, true)); - } + events.add(new MessageDeleteEvent(hostAddr, msgId, + time, true)); + } else if (action.equals(REMOVE)) { msgId = lineScan.next(); - hostAddr = getHostAddress(lineScan.next()); - events.add(new MessageDeleteEvent(hostAddr, msgId, - time, false)); + hostAddr = getHostAddress(lineScan.next()); + events.add(new MessageDeleteEvent(hostAddr, msgId, + time, false)); } else if (action.equals(CONNECTION)) { String connEventType; @@ -130,12 +130,12 @@ else if (action.equals(CONNECTION)) { hostAddr = getHostAddress(lineScan.next()); host2Addr = getHostAddress(lineScan.next()); connEventType = lineScan.next(); - + String interfaceId = null; if (lineScan.hasNext()) { interfaceId = lineScan.next(); - } - + } + if (connEventType.equalsIgnoreCase(CONNECTION_UP)) { isUp = true; } @@ -143,93 +143,93 @@ else if (connEventType.equalsIgnoreCase(CONNECTION_DOWN)) { isUp = false; } else { - throw new SimError("Unknown up/down value '" + + throw new SimError("Unknown up/down value '" + connEventType + "'"); } - - ConnectionEvent ce = new ConnectionEvent(hostAddr, + + ConnectionEvent ce = new ConnectionEvent(hostAddr, host2Addr, interfaceId, isUp, time); - + events.add(ce); - } + } else { msgId = lineScan.next(); - hostAddr = getHostAddress(lineScan.next()); - - host2Addr = getHostAddress(lineScan.next()); - - if (action.equals(CREATE)){ - int size = lineScan.nextInt(); - int respSize = 0; - if (lineScan.hasNextInt()) { - respSize = lineScan.nextInt(); - } - events.add(new MessageCreateEvent(hostAddr, host2Addr, - msgId, size, respSize, time)); - } - else { - int stage = -1; - if (action.equals(SEND)) { - stage = MessageRelayEvent.SENDING; - } - else if (action.equals(DELIVERED)) { - stage = MessageRelayEvent.TRANSFERRED; - } - else if (action.equals(ABORT)) { - stage = MessageRelayEvent.ABORTED; - } - else { - throw new SimError("Unknown action '" + action + - "' in external events"); - } - events.add(new MessageRelayEvent(hostAddr, host2Addr, - msgId, time, stage)); - } - } - // discard the newline in the end - if (lineScan.hasNextLine()) { - lineScan.nextLine(); // TODO: test + hostAddr = getHostAddress(lineScan.next()); + + host2Addr = getHostAddress(lineScan.next()); + + if (action.equals(CREATE)){ + int size = lineScan.nextInt(); + int respSize = 0; + if (lineScan.hasNextInt()) { + respSize = lineScan.nextInt(); + } + events.add(new MessageCreateEvent(hostAddr, host2Addr, + msgId, size, respSize, time)); + } + else { + int stage = -1; + if (action.equals(SEND)) { + stage = MessageRelayEvent.SENDING; + } + else if (action.equals(DELIVERED)) { + stage = MessageRelayEvent.TRANSFERRED; + } + else if (action.equals(ABORT)) { + stage = MessageRelayEvent.ABORTED; + } + else { + throw new SimError("Unknown action '" + action + + "' in external events"); + } + events.add(new MessageRelayEvent(hostAddr, host2Addr, + msgId, time, stage)); + } + } + // discard the newline in the end + if (lineScan.hasNextLine()) { + lineScan.nextLine(); // TODO: test } eventsRead++; - if (eventsRead < nrof) { + if (eventsRead < nrof) { line = this.reader.readLine(); - } - } catch (Exception e) { - throw new SimError("Can't parse external event " + - (eventsRead+1) + " from '" + line + "'", e); - } - } - - return events; - } - - /** - * Parses a host address from a hostId string (the numeric part after - * optional non-numeric part). - * @param hostId The id to parse the address from - * @return The address - * @throws SimError if no address could be parsed from the id - */ - private int getHostAddress(String hostId) { - String addressPart = ""; - if (hostId.matches("^\\d+$")) { - addressPart = hostId; // host id is only the address - } - else if (hostId.matches("^\\D+\\d+$")) { - String [] parts = hostId.split("\\D"); - addressPart = parts[parts.length-1]; // last occurence is the addr - } - else { - throw new SimError("Invalid host ID '" + hostId + "'"); - } - - return Integer.parseInt(addressPart); - } - - public void close() { + } + } catch (Exception e) { + throw new SimError("Can't parse external event " + + (eventsRead+1) + " from '" + line + "'", e); + } + } + + return events; + } + + /** + * Parses a host address from a hostId string (the numeric part after + * optional non-numeric part). + * @param hostId The id to parse the address from + * @return The address + * @throws SimError if no address could be parsed from the id + */ + private int getHostAddress(String hostId) { + String addressPart = ""; + if (hostId.matches("^\\d+$")) { + addressPart = hostId; // host id is only the address + } + else if (hostId.matches("^\\D+\\d+$")) { + String [] parts = hostId.split("\\D"); + addressPart = parts[parts.length-1]; // last occurence is the addr + } + else { + throw new SimError("Invalid host ID '" + hostId + "'"); + } + + return Integer.parseInt(addressPart); + } + + public void close() { try { this.reader.close(); - } catch (IOException e) {} - } - -} + } catch (IOException e) {} + } + +} diff --git a/input/WKTMapReader.java b/input/WKTMapReader.java index 24ac27ec6..b5790dad9 100644 --- a/input/WKTMapReader.java +++ b/input/WKTMapReader.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - +package input; + import java.io.File; import java.io.FileReader; import java.io.IOException; @@ -16,144 +16,144 @@ import movement.map.MapNode; import movement.map.SimMap; import core.Coord; - -/** - * "Well-known text syntax" map data reader.
- * Note: Understands only LINESTRINGs and - * MULTILINESTRINGs. Skips all POINT data. - * Other data causes IOException. - */ -public class WKTMapReader extends WKTReader { - private Hashtable nodes; - /** are all paths bidirectional */ - private boolean bidirectionalPaths = true; - private int nodeType = -1; - - /** - * Constructor. Creates a new WKT reader ready for addPaths() calls. - * @param bidi If true, all read paths are set bidirectional (i.e. if node A - * is a neighbor of node B, node B is also a neighbor of node A). - */ - public WKTMapReader(boolean bidi) { - this.bidirectionalPaths = bidi; - this.nodes = new Hashtable(); - } - - /** - * Sets bidirectional paths on/off. - * @param bidi If true, all paths are set bidirectional (false -> not) - */ - public void setBidirectional(boolean bidi) { - this.bidirectionalPaths = bidi; - } - - /** - * Returns the map nodes that were read in a collection - * @return the map nodes that were read in a collection - */ - public Collection getNodes() { - return this.nodes.values(); - } - - /** - * Returns the original Map object that was used to read the map - * @return the original Map object that was used to read the map - */ - public Map getNodesHash() { - return this.nodes; - } - - /** - * Returns new a SimMap that is based on the read map - * @return new a SimMap that is based on the read map - */ - public SimMap getMap() { - return new SimMap(this.nodes); - } - - /** - * Adds paths to the map and adds given type to all nodes' type. - * @param file The file where the WKT data is read from - * @param type The type to use (integer value, see class {@link MapNode})) - * @throws IOException If something went wrong while reading the file - */ - public void addPaths(File file, int type) throws IOException { - addPaths(new FileReader(file), type); - } - - - /** - * Add paths to current path set. Adding paths multiple times - * has the same result as concatenating the data before adding it. - * @param input Reader where the WKT data is read from - * @param nodeType The type to use (integer value, see class - * {@link MapNode})) - * @throws IOException if something went wrong with reading from the input - */ - public void addPaths(Reader input, int nodeType) throws IOException { - this.nodeType = nodeType; - String type; - String contents; - - init(input); - - while((type = nextType()) != null) { - if (type.equals(LINESTRING)) { - contents = readNestedContents(); - updateMap(parseLineString(contents)); - } - else if (type.equals(MULTILINESTRING)) { - for (List list : parseMultilinestring()) { - updateMap(list); - } - } - else { - // known type but not interesting -> skip - readNestedContents(); - } - } - } - - /** - * Updates simulation map with coordinates in the list - * @param coords The list of coordinates - */ - private void updateMap(List coords) { - MapNode previousNode = null; - for (Coord c : coords) { - previousNode = createOrUpdateNode(c, previousNode); - } - } - - /** - * Creates or updates a node that is in location c and next to - * node previous - * @param c The location coordinates of the node - * @param previous Previous node whose neighbor node at c is - * @return The created/updated node - */ - private MapNode createOrUpdateNode(Coord c, MapNode previous) { - MapNode n = null; - - n = nodes.get(c); // try to get the node at that location - - if (n == null) { // no node in that location -> create new - n = new MapNode(c); - nodes.put(c, n); - } - - if (previous != null) { - n.addNeighbor(previous); - if (bidirectionalPaths) { - previous.addNeighbor(n); - } - } - - if (nodeType != -1) { - n.addType(nodeType); - } - - return n; - } - -} + +/** + * "Well-known text syntax" map data reader.
+ * Note: Understands only LINESTRINGs and + * MULTILINESTRINGs. Skips all POINT data. + * Other data causes IOException. + */ +public class WKTMapReader extends WKTReader { + private Hashtable nodes; + /** are all paths bidirectional */ + private boolean bidirectionalPaths = true; + private int nodeType = -1; + + /** + * Constructor. Creates a new WKT reader ready for addPaths() calls. + * @param bidi If true, all read paths are set bidirectional (i.e. if node A + * is a neighbor of node B, node B is also a neighbor of node A). + */ + public WKTMapReader(boolean bidi) { + this.bidirectionalPaths = bidi; + this.nodes = new Hashtable(); + } + + /** + * Sets bidirectional paths on/off. + * @param bidi If true, all paths are set bidirectional (false -> not) + */ + public void setBidirectional(boolean bidi) { + this.bidirectionalPaths = bidi; + } + + /** + * Returns the map nodes that were read in a collection + * @return the map nodes that were read in a collection + */ + public Collection getNodes() { + return this.nodes.values(); + } + + /** + * Returns the original Map object that was used to read the map + * @return the original Map object that was used to read the map + */ + public Map getNodesHash() { + return this.nodes; + } + + /** + * Returns new a SimMap that is based on the read map + * @return new a SimMap that is based on the read map + */ + public SimMap getMap() { + return new SimMap(this.nodes); + } + + /** + * Adds paths to the map and adds given type to all nodes' type. + * @param file The file where the WKT data is read from + * @param type The type to use (integer value, see class {@link MapNode})) + * @throws IOException If something went wrong while reading the file + */ + public void addPaths(File file, int type) throws IOException { + addPaths(new FileReader(file), type); + } + + + /** + * Add paths to current path set. Adding paths multiple times + * has the same result as concatenating the data before adding it. + * @param input Reader where the WKT data is read from + * @param nodeType The type to use (integer value, see class + * {@link MapNode})) + * @throws IOException if something went wrong with reading from the input + */ + public void addPaths(Reader input, int nodeType) throws IOException { + this.nodeType = nodeType; + String type; + String contents; + + init(input); + + while((type = nextType()) != null) { + if (type.equals(LINESTRING)) { + contents = readNestedContents(); + updateMap(parseLineString(contents)); + } + else if (type.equals(MULTILINESTRING)) { + for (List list : parseMultilinestring()) { + updateMap(list); + } + } + else { + // known type but not interesting -> skip + readNestedContents(); + } + } + } + + /** + * Updates simulation map with coordinates in the list + * @param coords The list of coordinates + */ + private void updateMap(List coords) { + MapNode previousNode = null; + for (Coord c : coords) { + previousNode = createOrUpdateNode(c, previousNode); + } + } + + /** + * Creates or updates a node that is in location c and next to + * node previous + * @param c The location coordinates of the node + * @param previous Previous node whose neighbor node at c is + * @return The created/updated node + */ + private MapNode createOrUpdateNode(Coord c, MapNode previous) { + MapNode n = null; + + n = nodes.get(c); // try to get the node at that location + + if (n == null) { // no node in that location -> create new + n = new MapNode(c); + nodes.put(c, n); + } + + if (previous != null) { + n.addNeighbor(previous); + if (bidirectionalPaths) { + previous.addNeighbor(n); + } + } + + if (nodeType != -1) { + n.addType(nodeType); + } + + return n; + } + +} diff --git a/input/WKTReader.java b/input/WKTReader.java index 2c8c83caf..d772d985a 100644 --- a/input/WKTReader.java +++ b/input/WKTReader.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package input; - +package input; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -15,313 +15,313 @@ import java.util.Scanner; import core.Coord; - -/** - * Class for reading "Well-known text syntax" files. See e.g. - * Wikipedia for - * WKT syntax details. For example, Open JUMP - * GIS program can save compatible data from many other formats.
- */ -public class WKTReader { - /** known WKT type LINESTRING */ - public static final String LINESTRING = "LINESTRING"; - /** known WKT type MULTILINESTRING */ - public static final String MULTILINESTRING = "MULTILINESTRING"; - /** known WKT type POINT */ - public static final String POINT = "POINT"; - - /** are all lines of the file read */ - private boolean done; - /** reader for the data */ - private BufferedReader reader; - - /** - * Read point data from a file - * @param file The file to read points from - * @return A list of coordinates read from the file - * @throws IOException if something went wrong while reading - */ - public List readPoints(File file) throws IOException { - return readPoints(new FileReader(file)); - } - - /** - * Read point data from a Reader - * @param r The Reader to read points from - * @return A list of coordinates that were read - * @throws IOException if something went wrong while reading - */ - public List readPoints(Reader r) throws IOException { - List points = new ArrayList(); - - String type; - init(r); - - while((type = nextType()) != null) { - if (type.equals(POINT)) { - points.add(parsePoint()); - } - else { - // known type but not interesting -> skip - readNestedContents(); - } - } - - return points; - } - - /** - * Read line (LINESTRING) data from a file - * @param file The file to read data from - * @return A list of coordinate lists read from the file - * @throws IOException if something went wrong while reading - */ - public List> readLines(File file) throws IOException { - List> lines = new ArrayList>(); - - String type; - init(new FileReader(file)); - - while((type = nextType()) != null) { - if (type.equals(LINESTRING)) { - lines.add(parseLineString(readNestedContents())); - } - else { - // known type but not interesting -> skip - readNestedContents(); - } - } - - return lines; - } - - - /** - * Initialize the reader to use a certain input reader - * @param input The input to use - */ - protected void init(Reader input) { - setDone(false); - reader = new BufferedReader(input); - } - - /** - * Returns the next type read from the reader given at init or null - * if no more types can be read - * @return the next type read from the reader given at init - * @throws IOException - */ - protected String nextType() throws IOException { - String type = null; - - while (!done && type == null) { - type = readWord(reader); - - if (type.length() < 1) { // discard empty lines - type = null; - continue; - } - } - - return type; - } - - /** - * Returns true if type is one of the known WKT types - * @param type The type to check - * @return true if type is one of the known WKT types - */ - protected boolean isKnownType(String type) { - if (type.equals(LINESTRING)) { - return true; - } - else if (type.equals(MULTILINESTRING)) { - return true; - } - else if (type.equals(POINT)) { - return true; - } - else { - return false; - } - } - - /** - * Reads a "word", ie whitespace delimited string of characters, from - * the reader - * @param r Reader to read the characters from - * @return The word that was read (or empty string if nothing was read) - * @throws IOException - */ - protected String readWord(Reader r) throws IOException { - StringBuffer buf = new StringBuffer(); - char c = skipAllWhitespace(r); - - // read non-whitespace part - while(c != (char)-1 && !Character.isWhitespace(c)) { - buf.append(c); - c = (char)r.read(); - } - - if (c == (char)-1) { - setDone(true); - } - return buf.toString(); - } - - /** - * Parses a MULTILINESTRING statement that has nested linestrings from - * the current reader - * @return List of parsed Coord lists - * @throws IOException - */ - protected List> parseMultilinestring() - throws IOException { - List> list = new ArrayList>(); - String multiContents = readNestedContents(reader); - StringReader r2 = new StringReader(multiContents); - String lineString = readNestedContents(r2); - - while (lineString.length() > 0) { - list.add(parseLineString(lineString)); - lineString = readNestedContents(r2); - } - - return list; - } - - /** - * Parses a WKT point data from the intialized reader - * @return Point data as a Coordinate - * @throws IOException if couldn't parse coordinate values - */ - protected Coord parsePoint() throws IOException { - String coords = readNestedContents(reader); - Scanner s = new Scanner(coords); - double x,y; - - try { - x = s.nextDouble(); - y = s.nextDouble(); - } catch (RuntimeException e) { - throw new IOException("Bad coordinate values: '" + coords + "'"); - } - - return new Coord(x,y); - } - - /** - * Reads and skips all characters until character "until" is read or - * end of stream is reached. Also the expected character is discarded. - * @param r Reader to read characters from - * @param until What character to expect - * @throws IOException - */ - protected void skipUntil(Reader r, char until) throws IOException { - char c; - do { - c = (char)r.read(); - } while (c != until && c != (char)-1); - } - - /** - * Skips all consecutive whitespace characters from reader - * @param r Reader where the whitespace is skipped - * @return First non-whitespace character read from the reader - * @throws IOException - */ - protected char skipAllWhitespace(Reader r) throws IOException { - char c; - do { - c = (char)r.read(); - } while (Character.isWhitespace(c) && c != (char)-1); - - return c; - } - - /** - * Reads everything from the first opening parenthesis until line that - * ends to a closing parenthesis and returns the contents in one string - * @param r Reader to read the input from - * @return The text between the parentheses - */ - public String readNestedContents(Reader r) throws IOException { - StringBuffer contents = new StringBuffer(); - int parOpen; // nrof open parentheses - char c = '\0'; - - skipUntil(r,'('); - parOpen = 1; - - while (c != (char)-1 && parOpen > 0) { - c = (char)r.read(); - if (c == '(') { - parOpen++; - } - if (c == ')') { - parOpen--; - } - if (Character.isWhitespace(c)) { - c = ' '; // convert all whitespace to basic space - } - contents.append(c); - } - - contents.deleteCharAt(contents.length()-1); // remove last ')' - return contents.toString(); - } - - /** - * Returns nested contents from the reader given at init - * @return nested contents from the reader given at init - * @throws IOException - * @see #readNestedContents(Reader) - */ - public String readNestedContents() throws IOException { - return readNestedContents(reader); - } - - /** - * Parses coordinate tuples from "LINESTRING" lines - * @param line String that contains the whole "LINESTRING"'s content - * @return List of coordinates parsed from the linestring - */ - protected List parseLineString(String line) { - List coords = new ArrayList(); - Scanner lineScan; - Scanner tupleScan; - double x,y; - Coord c; - - lineScan = new Scanner(line); - lineScan.useDelimiter(","); - - while (lineScan.hasNext()) { - tupleScan = new Scanner(lineScan.next()); - x = Double.parseDouble(tupleScan.next()); - y = Double.parseDouble(tupleScan.next()); - c = new Coord(x,y); - - coords.add(c); - } - - return coords; - } - - /** - * Returns true if the whole file has been read - * @return true if the whole file has been read - */ - protected boolean isDone() { - return this.done; - } - - /** - * Sets the "is file read" state - * @param done If true, reading is done - */ - protected void setDone(boolean done) { - this.done = done; - } - -} + +/** + * Class for reading "Well-known text syntax" files. See e.g. + * Wikipedia for + * WKT syntax details. For example, Open JUMP + * GIS program can save compatible data from many other formats.
+ */ +public class WKTReader { + /** known WKT type LINESTRING */ + public static final String LINESTRING = "LINESTRING"; + /** known WKT type MULTILINESTRING */ + public static final String MULTILINESTRING = "MULTILINESTRING"; + /** known WKT type POINT */ + public static final String POINT = "POINT"; + + /** are all lines of the file read */ + private boolean done; + /** reader for the data */ + private BufferedReader reader; + + /** + * Read point data from a file + * @param file The file to read points from + * @return A list of coordinates read from the file + * @throws IOException if something went wrong while reading + */ + public List readPoints(File file) throws IOException { + return readPoints(new FileReader(file)); + } + + /** + * Read point data from a Reader + * @param r The Reader to read points from + * @return A list of coordinates that were read + * @throws IOException if something went wrong while reading + */ + public List readPoints(Reader r) throws IOException { + List points = new ArrayList(); + + String type; + init(r); + + while((type = nextType()) != null) { + if (type.equals(POINT)) { + points.add(parsePoint()); + } + else { + // known type but not interesting -> skip + readNestedContents(); + } + } + + return points; + } + + /** + * Read line (LINESTRING) data from a file + * @param file The file to read data from + * @return A list of coordinate lists read from the file + * @throws IOException if something went wrong while reading + */ + public List> readLines(File file) throws IOException { + List> lines = new ArrayList>(); + + String type; + init(new FileReader(file)); + + while((type = nextType()) != null) { + if (type.equals(LINESTRING)) { + lines.add(parseLineString(readNestedContents())); + } + else { + // known type but not interesting -> skip + readNestedContents(); + } + } + + return lines; + } + + + /** + * Initialize the reader to use a certain input reader + * @param input The input to use + */ + protected void init(Reader input) { + setDone(false); + reader = new BufferedReader(input); + } + + /** + * Returns the next type read from the reader given at init or null + * if no more types can be read + * @return the next type read from the reader given at init + * @throws IOException + */ + protected String nextType() throws IOException { + String type = null; + + while (!done && type == null) { + type = readWord(reader); + + if (type.length() < 1) { // discard empty lines + type = null; + continue; + } + } + + return type; + } + + /** + * Returns true if type is one of the known WKT types + * @param type The type to check + * @return true if type is one of the known WKT types + */ + protected boolean isKnownType(String type) { + if (type.equals(LINESTRING)) { + return true; + } + else if (type.equals(MULTILINESTRING)) { + return true; + } + else if (type.equals(POINT)) { + return true; + } + else { + return false; + } + } + + /** + * Reads a "word", ie whitespace delimited string of characters, from + * the reader + * @param r Reader to read the characters from + * @return The word that was read (or empty string if nothing was read) + * @throws IOException + */ + protected String readWord(Reader r) throws IOException { + StringBuffer buf = new StringBuffer(); + char c = skipAllWhitespace(r); + + // read non-whitespace part + while(c != (char)-1 && !Character.isWhitespace(c)) { + buf.append(c); + c = (char)r.read(); + } + + if (c == (char)-1) { + setDone(true); + } + return buf.toString(); + } + + /** + * Parses a MULTILINESTRING statement that has nested linestrings from + * the current reader + * @return List of parsed Coord lists + * @throws IOException + */ + protected List> parseMultilinestring() + throws IOException { + List> list = new ArrayList>(); + String multiContents = readNestedContents(reader); + StringReader r2 = new StringReader(multiContents); + String lineString = readNestedContents(r2); + + while (lineString.length() > 0) { + list.add(parseLineString(lineString)); + lineString = readNestedContents(r2); + } + + return list; + } + + /** + * Parses a WKT point data from the intialized reader + * @return Point data as a Coordinate + * @throws IOException if couldn't parse coordinate values + */ + protected Coord parsePoint() throws IOException { + String coords = readNestedContents(reader); + Scanner s = new Scanner(coords); + double x,y; + + try { + x = s.nextDouble(); + y = s.nextDouble(); + } catch (RuntimeException e) { + throw new IOException("Bad coordinate values: '" + coords + "'"); + } + + return new Coord(x,y); + } + + /** + * Reads and skips all characters until character "until" is read or + * end of stream is reached. Also the expected character is discarded. + * @param r Reader to read characters from + * @param until What character to expect + * @throws IOException + */ + protected void skipUntil(Reader r, char until) throws IOException { + char c; + do { + c = (char)r.read(); + } while (c != until && c != (char)-1); + } + + /** + * Skips all consecutive whitespace characters from reader + * @param r Reader where the whitespace is skipped + * @return First non-whitespace character read from the reader + * @throws IOException + */ + protected char skipAllWhitespace(Reader r) throws IOException { + char c; + do { + c = (char)r.read(); + } while (Character.isWhitespace(c) && c != (char)-1); + + return c; + } + + /** + * Reads everything from the first opening parenthesis until line that + * ends to a closing parenthesis and returns the contents in one string + * @param r Reader to read the input from + * @return The text between the parentheses + */ + public String readNestedContents(Reader r) throws IOException { + StringBuffer contents = new StringBuffer(); + int parOpen; // nrof open parentheses + char c = '\0'; + + skipUntil(r,'('); + parOpen = 1; + + while (c != (char)-1 && parOpen > 0) { + c = (char)r.read(); + if (c == '(') { + parOpen++; + } + if (c == ')') { + parOpen--; + } + if (Character.isWhitespace(c)) { + c = ' '; // convert all whitespace to basic space + } + contents.append(c); + } + + contents.deleteCharAt(contents.length()-1); // remove last ')' + return contents.toString(); + } + + /** + * Returns nested contents from the reader given at init + * @return nested contents from the reader given at init + * @throws IOException + * @see #readNestedContents(Reader) + */ + public String readNestedContents() throws IOException { + return readNestedContents(reader); + } + + /** + * Parses coordinate tuples from "LINESTRING" lines + * @param line String that contains the whole "LINESTRING"'s content + * @return List of coordinates parsed from the linestring + */ + protected List parseLineString(String line) { + List coords = new ArrayList(); + Scanner lineScan; + Scanner tupleScan; + double x,y; + Coord c; + + lineScan = new Scanner(line); + lineScan.useDelimiter(","); + + while (lineScan.hasNext()) { + tupleScan = new Scanner(lineScan.next()); + x = Double.parseDouble(tupleScan.next()); + y = Double.parseDouble(tupleScan.next()); + c = new Coord(x,y); + + coords.add(c); + } + + return coords; + } + + /** + * Returns true if the whole file has been read + * @return true if the whole file has been read + */ + protected boolean isDone() { + return this.done; + } + + /** + * Sets the "is file read" state + * @param done If true, reading is done + */ + protected void setDone(boolean done) { + this.done = done; + } + +} diff --git a/input/package.html b/input/package.html index ab7fd2259..f0a28be85 100644 --- a/input/package.html +++ b/input/package.html @@ -1,8 +1,8 @@ - - - - -Provides interfaces and classes for reading input data from external sources. - - - \ No newline at end of file + + + + +Provides interfaces and classes for reading input data from external sources. + + + diff --git a/interfaces/ConnectivityGrid.java b/interfaces/ConnectivityGrid.java index 4ee1082ae..ca24d16d1 100644 --- a/interfaces/ConnectivityGrid.java +++ b/interfaces/ConnectivityGrid.java @@ -1,323 +1,323 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package interfaces; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; - -import movement.MovementModel; - -import core.Coord; -import core.DTNSim; -import core.NetworkInterface; -import core.Settings; -import core.SettingsError; -import core.World; - -/** - *

- * Overlay grid of the world where each interface is put on a cell depending - * of its location. This is used in cell-based optimization of connecting - * the interfaces.

- * - *

The idea in short:
- * Instead of checking for every interface if some of the other interfaces are close - * enough (this approach obviously doesn't scale) we check only interfaces that - * are "close enough" to be possibly connected. Being close enough is - * determined by keeping track of the approximate location of the interfaces - * by storing them in overlay grid's cells and updating the cell information - * every time the interfaces move. If two interfaces are in the same cell or in - * neighboring cells, they have a chance of being close enough for - * connection. Then only that subset of interfaces is checked for possible - * connectivity. - *

- *

- * Note: this class does NOT support negative - * coordinates. Also, it makes sense to normalize the coordinates to start - * from zero to conserve memory. - */ -public class ConnectivityGrid extends ConnectivityOptimizer { - - /** - * Cell based optimization cell size multiplier -setting id ({@value}). - * Used in {@link World#OPTIMIZATION_SETTINGS_NS} name space. - * Single ConnectivityCell's size is the biggest radio range times this. - * Larger values save memory and decrease startup time but may result in - * slower simulation. - * Default value is {@link #DEF_CON_CELL_SIZE_MULT}. - * Smallest accepted value is 1. - */ - public static final String CELL_SIZE_MULT_S = "cellSizeMult"; - /** default value for cell size multiplier ({@value}) */ - public static final int DEF_CON_CELL_SIZE_MULT = 5; - - private GridCell[][] cells; - private HashMap ginterfaces; - private int cellSize; - private int rows; - private int cols; - private static int worldSizeX; - private static int worldSizeY; - private static int cellSizeMultiplier; - - static HashMap gridobjects; - - static { - DTNSim.registerForReset(ConnectivityGrid.class.getCanonicalName()); - reset(); - } - - public static void reset() { - gridobjects = new HashMap(); - - Settings s = new Settings(MovementModel.MOVEMENT_MODEL_NS); - int [] worldSize = s.getCsvInts(MovementModel.WORLD_SIZE,2); - worldSizeX = worldSize[0]; - worldSizeY = worldSize[1]; - - s.setNameSpace(World.OPTIMIZATION_SETTINGS_NS); - if (s.contains(CELL_SIZE_MULT_S)) { - cellSizeMultiplier = s.getInt(CELL_SIZE_MULT_S); - } - else { - cellSizeMultiplier = DEF_CON_CELL_SIZE_MULT; - } - if (cellSizeMultiplier < 1) { - throw new SettingsError("Too small value (" + cellSizeMultiplier + - ") for " + World.OPTIMIZATION_SETTINGS_NS + - "." + CELL_SIZE_MULT_S); - } - } - - /** - * Creates a new overlay connectivity grid - * @param cellSize Cell's edge's length (must be larger than the largest - * radio coverage's diameter) - */ - private ConnectivityGrid(int cellSize) { - this.rows = worldSizeY/cellSize + 1; - this.cols = worldSizeX/cellSize + 1; - // leave empty cells on both sides to make neighbor search easier - this.cells = new GridCell[rows+2][cols+2]; - this.cellSize = cellSize; - - for (int i=0; i(); - } - - /** - * Returns a connectivity grid object based on a hash value - * @param key A hash value that separates different interfaces from each other - * @param maxRange Maximum range used by the radio technology using this - * connectivity grid. - * @return The connectivity grid object for a specific interface - */ - public static ConnectivityGrid ConnectivityGridFactory(int key, - double maxRange) { - if (gridobjects.containsKey((Integer)key)) { - return (ConnectivityGrid)gridobjects.get((Integer)key); - } else { - ConnectivityGrid newgrid = - new ConnectivityGrid((int)Math.ceil(maxRange * - cellSizeMultiplier)); - gridobjects.put((Integer)key,newgrid); - return newgrid; - } - } - - /** - * Adds a network interface to the overlay grid - * @param ni The new network interface - */ - public void addInterface(NetworkInterface ni) { - GridCell c = cellFromCoord(ni.getLocation()); - c.addInterface(ni); - ginterfaces.put(ni,c); - } - - /** - * Removes a network interface from the overlay grid - * @param ni The interface to be removed - */ - public void removeInterface(NetworkInterface ni) { - GridCell c = ginterfaces.get(ni); - if (c != null) { - c.removeInterface(ni); - } - ginterfaces.remove(ni); - } - - /** - * Adds interfaces to overlay grid - * @param interfaces Collection of interfaces to add - */ - public void addInterfaces(Collection interfaces) { - for (NetworkInterface n : interfaces) { - addInterface(n); - } - } - - /** - * Checks and updates (if necessary) interface's position in the grid - * @param ni The interface to update - */ - public void updateLocation(NetworkInterface ni) { - GridCell oldCell = (GridCell)ginterfaces.get(ni); - GridCell newCell = cellFromCoord(ni.getLocation()); - - if (newCell != oldCell) { - oldCell.moveInterface(ni, newCell); - ginterfaces.put(ni,newCell); - } - } - - /** - * Finds all neighboring cells and the cell itself based on the coordinates - * @param c The coordinates - * @return Array of neighboring cells - */ - private GridCell[] getNeighborCellsByCoord(Coord c) { - // +1 due empty cells on both sides of the matrix - int row = (int)(c.getY()/cellSize) + 1; - int col = (int)(c.getX()/cellSize) + 1; - return getNeighborCells(row,col); - } - - /** - * Returns an array of Cells that contains the neighbors of a certain - * cell and the cell itself. - * @param row Row index of the cell - * @param col Column index of the cell - * @return Array of neighboring Cells - */ - private GridCell[] getNeighborCells(int row, int col) { - return new GridCell[] { - cells[row-1][col-1],cells[row-1][col],cells[row-1][col+1],//1st row - cells[row][col-1],cells[row][col],cells[row][col+1],//2nd row - cells[row+1][col-1],cells[row+1][col],cells[row+1][col+1]//3rd row - }; - } - - /** - * Get the cell having the specific coordinates - * @param c Coordinates - * @return The cell - */ - private GridCell cellFromCoord(Coord c) { - // +1 due empty cells on both sides of the matrix - int row = (int)(c.getY()/cellSize) + 1; - int col = (int)(c.getX()/cellSize) + 1; - - assert row > 0 && row <= rows && col > 0 && col <= cols : "Location " + - c + " is out of world's bounds"; - - return this.cells[row][col]; - } - - /** - * Returns all interfaces that use the same technology and channel - */ - public Collection getAllInterfaces() { - return (Collection)ginterfaces.keySet(); - } - - /** - * Returns all interfaces that are "near" (i.e., in neighboring grid cells) - * and use the same technology and channel as the given interface - * @param ni The interface whose neighboring interfaces are returned - * @return List of near interfaces - */ - public Collection getNearInterfaces( - NetworkInterface ni) { - ArrayList niList = new ArrayList(); - GridCell loc = (GridCell)ginterfaces.get(ni); - - if (loc != null) { - GridCell[] neighbors = - getNeighborCellsByCoord(ni.getLocation()); - for (int i=0; i < neighbors.length; i++) { - niList.addAll(neighbors[i].getInterfaces()); - } - } - - return niList; - } - - - /** - * Returns a string representation of the ConnectivityCells object - * @return a string representation of the ConnectivityCells object - */ - public String toString() { - return getClass().getSimpleName() + " of size " + - this.cols + "x" + this.rows + ", cell size=" + this.cellSize; - } - - /** - * A single cell in the cell grid. Contains the interfaces that are - * currently in that part of the grid. - */ - public class GridCell { - // how large array is initially chosen - private static final int EXPECTED_INTERFACE_COUNT = 5; - private ArrayList interfaces; - - private GridCell() { - this.interfaces = new ArrayList( - EXPECTED_INTERFACE_COUNT); - } - - /** - * Returns a list of of interfaces in this cell - * @return a list of of interfaces in this cell - */ - public ArrayList getInterfaces() { - return this.interfaces; - } - - /** - * Adds an interface to this cell - * @param ni The interface to add - */ - public void addInterface(NetworkInterface ni) { - this.interfaces.add(ni); - } - - /** - * Removes an interface from this cell - * @param ni The interface to remove - */ - public void removeInterface(NetworkInterface ni) { - this.interfaces.remove(ni); - } - - /** - * Moves a interface in a Cell to another Cell - * @param ni The interface to move - * @param to The cell where the interface should be moved to - */ - public void moveInterface(NetworkInterface ni, GridCell to) { - to.addInterface(ni); - boolean removeOk = this.interfaces.remove(ni); - assert removeOk : "interface " + ni + - " not found from cell with " + interfaces.toString(); - } - - /** - * Returns a string representation of the cell - * @return a string representation of the cell - */ - public String toString() { - return getClass().getSimpleName() + " with " + - this.interfaces.size() + " interfaces :" + this.interfaces; - } - } - -} \ No newline at end of file + * Released under GPLv3. See LICENSE.txt for details. + */ +package interfaces; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; + +import movement.MovementModel; + +import core.Coord; +import core.DTNSim; +import core.NetworkInterface; +import core.Settings; +import core.SettingsError; +import core.World; + +/** + *

+ * Overlay grid of the world where each interface is put on a cell depending + * of its location. This is used in cell-based optimization of connecting + * the interfaces.

+ * + *

The idea in short:
+ * Instead of checking for every interface if some of the other interfaces are close + * enough (this approach obviously doesn't scale) we check only interfaces that + * are "close enough" to be possibly connected. Being close enough is + * determined by keeping track of the approximate location of the interfaces + * by storing them in overlay grid's cells and updating the cell information + * every time the interfaces move. If two interfaces are in the same cell or in + * neighboring cells, they have a chance of being close enough for + * connection. Then only that subset of interfaces is checked for possible + * connectivity. + *

+ *

+ * Note: this class does NOT support negative + * coordinates. Also, it makes sense to normalize the coordinates to start + * from zero to conserve memory. + */ +public class ConnectivityGrid extends ConnectivityOptimizer { + + /** + * Cell based optimization cell size multiplier -setting id ({@value}). + * Used in {@link World#OPTIMIZATION_SETTINGS_NS} name space. + * Single ConnectivityCell's size is the biggest radio range times this. + * Larger values save memory and decrease startup time but may result in + * slower simulation. + * Default value is {@link #DEF_CON_CELL_SIZE_MULT}. + * Smallest accepted value is 1. + */ + public static final String CELL_SIZE_MULT_S = "cellSizeMult"; + /** default value for cell size multiplier ({@value}) */ + public static final int DEF_CON_CELL_SIZE_MULT = 5; + + private GridCell[][] cells; + private HashMap ginterfaces; + private int cellSize; + private int rows; + private int cols; + private static int worldSizeX; + private static int worldSizeY; + private static int cellSizeMultiplier; + + static HashMap gridobjects; + + static { + DTNSim.registerForReset(ConnectivityGrid.class.getCanonicalName()); + reset(); + } + + public static void reset() { + gridobjects = new HashMap(); + + Settings s = new Settings(MovementModel.MOVEMENT_MODEL_NS); + int [] worldSize = s.getCsvInts(MovementModel.WORLD_SIZE,2); + worldSizeX = worldSize[0]; + worldSizeY = worldSize[1]; + + s.setNameSpace(World.OPTIMIZATION_SETTINGS_NS); + if (s.contains(CELL_SIZE_MULT_S)) { + cellSizeMultiplier = s.getInt(CELL_SIZE_MULT_S); + } + else { + cellSizeMultiplier = DEF_CON_CELL_SIZE_MULT; + } + if (cellSizeMultiplier < 1) { + throw new SettingsError("Too small value (" + cellSizeMultiplier + + ") for " + World.OPTIMIZATION_SETTINGS_NS + + "." + CELL_SIZE_MULT_S); + } + } + + /** + * Creates a new overlay connectivity grid + * @param cellSize Cell's edge's length (must be larger than the largest + * radio coverage's diameter) + */ + private ConnectivityGrid(int cellSize) { + this.rows = worldSizeY/cellSize + 1; + this.cols = worldSizeX/cellSize + 1; + // leave empty cells on both sides to make neighbor search easier + this.cells = new GridCell[rows+2][cols+2]; + this.cellSize = cellSize; + + for (int i=0; i(); + } + + /** + * Returns a connectivity grid object based on a hash value + * @param key A hash value that separates different interfaces from each other + * @param maxRange Maximum range used by the radio technology using this + * connectivity grid. + * @return The connectivity grid object for a specific interface + */ + public static ConnectivityGrid ConnectivityGridFactory(int key, + double maxRange) { + if (gridobjects.containsKey((Integer)key)) { + return (ConnectivityGrid)gridobjects.get((Integer)key); + } else { + ConnectivityGrid newgrid = + new ConnectivityGrid((int)Math.ceil(maxRange * + cellSizeMultiplier)); + gridobjects.put((Integer)key,newgrid); + return newgrid; + } + } + + /** + * Adds a network interface to the overlay grid + * @param ni The new network interface + */ + public void addInterface(NetworkInterface ni) { + GridCell c = cellFromCoord(ni.getLocation()); + c.addInterface(ni); + ginterfaces.put(ni,c); + } + + /** + * Removes a network interface from the overlay grid + * @param ni The interface to be removed + */ + public void removeInterface(NetworkInterface ni) { + GridCell c = ginterfaces.get(ni); + if (c != null) { + c.removeInterface(ni); + } + ginterfaces.remove(ni); + } + + /** + * Adds interfaces to overlay grid + * @param interfaces Collection of interfaces to add + */ + public void addInterfaces(Collection interfaces) { + for (NetworkInterface n : interfaces) { + addInterface(n); + } + } + + /** + * Checks and updates (if necessary) interface's position in the grid + * @param ni The interface to update + */ + public void updateLocation(NetworkInterface ni) { + GridCell oldCell = (GridCell)ginterfaces.get(ni); + GridCell newCell = cellFromCoord(ni.getLocation()); + + if (newCell != oldCell) { + oldCell.moveInterface(ni, newCell); + ginterfaces.put(ni,newCell); + } + } + + /** + * Finds all neighboring cells and the cell itself based on the coordinates + * @param c The coordinates + * @return Array of neighboring cells + */ + private GridCell[] getNeighborCellsByCoord(Coord c) { + // +1 due empty cells on both sides of the matrix + int row = (int)(c.getY()/cellSize) + 1; + int col = (int)(c.getX()/cellSize) + 1; + return getNeighborCells(row,col); + } + + /** + * Returns an array of Cells that contains the neighbors of a certain + * cell and the cell itself. + * @param row Row index of the cell + * @param col Column index of the cell + * @return Array of neighboring Cells + */ + private GridCell[] getNeighborCells(int row, int col) { + return new GridCell[] { + cells[row-1][col-1],cells[row-1][col],cells[row-1][col+1],//1st row + cells[row][col-1],cells[row][col],cells[row][col+1],//2nd row + cells[row+1][col-1],cells[row+1][col],cells[row+1][col+1]//3rd row + }; + } + + /** + * Get the cell having the specific coordinates + * @param c Coordinates + * @return The cell + */ + private GridCell cellFromCoord(Coord c) { + // +1 due empty cells on both sides of the matrix + int row = (int)(c.getY()/cellSize) + 1; + int col = (int)(c.getX()/cellSize) + 1; + + assert row > 0 && row <= rows && col > 0 && col <= cols : "Location " + + c + " is out of world's bounds"; + + return this.cells[row][col]; + } + + /** + * Returns all interfaces that use the same technology and channel + */ + public Collection getAllInterfaces() { + return (Collection)ginterfaces.keySet(); + } + + /** + * Returns all interfaces that are "near" (i.e., in neighboring grid cells) + * and use the same technology and channel as the given interface + * @param ni The interface whose neighboring interfaces are returned + * @return List of near interfaces + */ + public Collection getNearInterfaces( + NetworkInterface ni) { + ArrayList niList = new ArrayList(); + GridCell loc = (GridCell)ginterfaces.get(ni); + + if (loc != null) { + GridCell[] neighbors = + getNeighborCellsByCoord(ni.getLocation()); + for (int i=0; i < neighbors.length; i++) { + niList.addAll(neighbors[i].getInterfaces()); + } + } + + return niList; + } + + + /** + * Returns a string representation of the ConnectivityCells object + * @return a string representation of the ConnectivityCells object + */ + public String toString() { + return getClass().getSimpleName() + " of size " + + this.cols + "x" + this.rows + ", cell size=" + this.cellSize; + } + + /** + * A single cell in the cell grid. Contains the interfaces that are + * currently in that part of the grid. + */ + public class GridCell { + // how large array is initially chosen + private static final int EXPECTED_INTERFACE_COUNT = 5; + private ArrayList interfaces; + + private GridCell() { + this.interfaces = new ArrayList( + EXPECTED_INTERFACE_COUNT); + } + + /** + * Returns a list of of interfaces in this cell + * @return a list of of interfaces in this cell + */ + public ArrayList getInterfaces() { + return this.interfaces; + } + + /** + * Adds an interface to this cell + * @param ni The interface to add + */ + public void addInterface(NetworkInterface ni) { + this.interfaces.add(ni); + } + + /** + * Removes an interface from this cell + * @param ni The interface to remove + */ + public void removeInterface(NetworkInterface ni) { + this.interfaces.remove(ni); + } + + /** + * Moves a interface in a Cell to another Cell + * @param ni The interface to move + * @param to The cell where the interface should be moved to + */ + public void moveInterface(NetworkInterface ni, GridCell to) { + to.addInterface(ni); + boolean removeOk = this.interfaces.remove(ni); + assert removeOk : "interface " + ni + + " not found from cell with " + interfaces.toString(); + } + + /** + * Returns a string representation of the cell + * @return a string representation of the cell + */ + public String toString() { + return getClass().getSimpleName() + " with " + + this.interfaces.size() + " interfaces :" + this.interfaces; + } + } + +} diff --git a/interfaces/ConnectivityOptimizer.java b/interfaces/ConnectivityOptimizer.java index 59e8b5290..1e1d81472 100644 --- a/interfaces/ConnectivityOptimizer.java +++ b/interfaces/ConnectivityOptimizer.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package interfaces; @@ -33,7 +33,7 @@ abstract public class ConnectivityOptimizer { /** * Finds all network interfaces that might be located so that they can be * connected with the network interface - * + * * @param ni network interface that needs to be connected * @return A collection of network interfaces within proximity */ diff --git a/interfaces/DistanceCapacityInterface.java b/interfaces/DistanceCapacityInterface.java index 83059869f..5070950ad 100644 --- a/interfaces/DistanceCapacityInterface.java +++ b/interfaces/DistanceCapacityInterface.java @@ -1,163 +1,163 @@ -/* +/* * Copyright 2014 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package interfaces; - -import java.util.Collection; -import core.Connection; -import core.NetworkInterface; -import core.Settings; -import core.VBRConnection; - -/** - * A Network Interface that that takes in to account he distance from the - * other (connected) interface when determining the capacity of the links. - * The distance-dependent transmission speeds are given as comma-separated - * values using setting {@link this#TRANSMIT_SPEEDS_S}. - */ -public class DistanceCapacityInterface extends NetworkInterface { - - /** - * Comma-separated list of speed values -setting id ({@value} ). The first - * value is the speed at distance 0 and the following are speeds at equal - * steps until the last one is the speed at the end of the transmit range ( - * {@link NetworkInterface#TRANSMIT_RANGE_S}). The speed between the steps - * is linearly interpolated. - */ - public static final String TRANSMIT_SPEEDS_S = "transmitSpeeds"; - - protected final int[] transmitSpeeds; - - /** - * Reads the interface settings from the Settings file - */ - public DistanceCapacityInterface(Settings s) { - super(s); - transmitSpeeds = s.getCsvInts(TRANSMIT_SPEEDS_S); - } - - /** - * Copy constructor - * @param ni the copied network interface object - */ - public DistanceCapacityInterface(DistanceCapacityInterface ni) { - super(ni); - transmitSpeeds = ni.transmitSpeeds; - } - - public NetworkInterface replicate() { - return new DistanceCapacityInterface(this); - } - - /** - * Tries to connect this host to another host. The other host must be - * active and within range of this host for the connection to succeed. - * @param anotherInterface The interface to connect to - */ - public void connect(NetworkInterface anotherInterface) { - if (isScanning() - && anotherInterface.getHost().isRadioActive() - && isWithinRange(anotherInterface) - && !isConnected(anotherInterface) - && (this != anotherInterface)) { - - Connection con = new VBRConnection(this.host, this, - anotherInterface.getHost(), anotherInterface); - connect(con,anotherInterface); - } - } - - /** - * Updates the state of current connections (i.e. tears down connections - * that are out of range and creates new ones). - */ - public void update() { - if (optimizer == null) { - return; /* nothing to do */ - } - - // First break the old ones - optimizer.updateLocation(this); - for (int i=0; i interfaces = - optimizer.getNearInterfaces(this); - for (NetworkInterface i : interfaces) { - connect(i); - } - - /* update all connections */ - for (Connection con : getConnections()) { - con.update(); - } - } - - /** - * Creates a connection to another host. This method does not do any checks - * on whether the other node is in range or active - * @param anotherInterface The interface to create the connection to - */ - public void createConnection(NetworkInterface anotherInterface) { - if (!isConnected(anotherInterface) && (this != anotherInterface)) { - Connection con = new VBRConnection(this.host, this, - anotherInterface.getHost(), anotherInterface); - connect(con,anotherInterface); - } - } - - /** - * Returns the transmit speed to another interface based on the - * distance to this interface - * @param ni The other network interface - */ - @Override - public int getTransmitSpeed(NetworkInterface ni) { - double distance; - double fractionIndex; - double decimal; - double speed; - int index; - - /* distance to the other interface */ - distance = ni.getLocation().distance(this.getLocation()); - - if (distance >= this.transmitRange) { - return 0; - } - - /* interpolate between the two speeds */ - fractionIndex = (distance / this.transmitRange) * - (this.transmitSpeeds.length - 1); - index = (int)(fractionIndex); - decimal = fractionIndex - index; - - speed = this.transmitSpeeds[index] * (1-decimal) + - this.transmitSpeeds[index + 1] * decimal; - - return (int)speed; - } - - /** - * Returns a string representation of the object. - * @return a string representation of the object. - */ - public String toString() { - return "DistanceCapacityInterface " + super.toString(); - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package interfaces; + +import java.util.Collection; +import core.Connection; +import core.NetworkInterface; +import core.Settings; +import core.VBRConnection; + +/** + * A Network Interface that that takes in to account he distance from the + * other (connected) interface when determining the capacity of the links. + * The distance-dependent transmission speeds are given as comma-separated + * values using setting {@link this#TRANSMIT_SPEEDS_S}. + */ +public class DistanceCapacityInterface extends NetworkInterface { + + /** + * Comma-separated list of speed values -setting id ({@value} ). The first + * value is the speed at distance 0 and the following are speeds at equal + * steps until the last one is the speed at the end of the transmit range ( + * {@link NetworkInterface#TRANSMIT_RANGE_S}). The speed between the steps + * is linearly interpolated. + */ + public static final String TRANSMIT_SPEEDS_S = "transmitSpeeds"; + + protected final int[] transmitSpeeds; + + /** + * Reads the interface settings from the Settings file + */ + public DistanceCapacityInterface(Settings s) { + super(s); + transmitSpeeds = s.getCsvInts(TRANSMIT_SPEEDS_S); + } + + /** + * Copy constructor + * @param ni the copied network interface object + */ + public DistanceCapacityInterface(DistanceCapacityInterface ni) { + super(ni); + transmitSpeeds = ni.transmitSpeeds; + } + + public NetworkInterface replicate() { + return new DistanceCapacityInterface(this); + } + + /** + * Tries to connect this host to another host. The other host must be + * active and within range of this host for the connection to succeed. + * @param anotherInterface The interface to connect to + */ + public void connect(NetworkInterface anotherInterface) { + if (isScanning() + && anotherInterface.getHost().isRadioActive() + && isWithinRange(anotherInterface) + && !isConnected(anotherInterface) + && (this != anotherInterface)) { + + Connection con = new VBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface); + connect(con,anotherInterface); + } + } + + /** + * Updates the state of current connections (i.e. tears down connections + * that are out of range and creates new ones). + */ + public void update() { + if (optimizer == null) { + return; /* nothing to do */ + } + + // First break the old ones + optimizer.updateLocation(this); + for (int i=0; i interfaces = + optimizer.getNearInterfaces(this); + for (NetworkInterface i : interfaces) { + connect(i); + } + + /* update all connections */ + for (Connection con : getConnections()) { + con.update(); + } + } + + /** + * Creates a connection to another host. This method does not do any checks + * on whether the other node is in range or active + * @param anotherInterface The interface to create the connection to + */ + public void createConnection(NetworkInterface anotherInterface) { + if (!isConnected(anotherInterface) && (this != anotherInterface)) { + Connection con = new VBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface); + connect(con,anotherInterface); + } + } + + /** + * Returns the transmit speed to another interface based on the + * distance to this interface + * @param ni The other network interface + */ + @Override + public int getTransmitSpeed(NetworkInterface ni) { + double distance; + double fractionIndex; + double decimal; + double speed; + int index; + + /* distance to the other interface */ + distance = ni.getLocation().distance(this.getLocation()); + + if (distance >= this.transmitRange) { + return 0; + } + + /* interpolate between the two speeds */ + fractionIndex = (distance / this.transmitRange) * + (this.transmitSpeeds.length - 1); + index = (int)(fractionIndex); + decimal = fractionIndex - index; + + speed = this.transmitSpeeds[index] * (1-decimal) + + this.transmitSpeeds[index + 1] * decimal; + + return (int)speed; + } + + /** + * Returns a string representation of the object. + * @return a string representation of the object. + */ + public String toString() { + return "DistanceCapacityInterface " + super.toString(); + } + +} diff --git a/interfaces/InterferenceLimitedInterface.java b/interfaces/InterferenceLimitedInterface.java index 90b9426c0..c18c6b979 100644 --- a/interfaces/InterferenceLimitedInterface.java +++ b/interfaces/InterferenceLimitedInterface.java @@ -1,166 +1,166 @@ -/* - * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package interfaces; - -import java.util.Collection; - -import core.Connection; -import core.NetworkInterface; -import core.Settings; -import core.VBRConnection; - -/** - * A simple Network Interface that provides a variable bit-rate service, where - * the bit-rate depends on the number of other transmitting stations within - * range The current transmit speed is updated only if there are ongoing - * transmissions. The configured transmit speed is the maximum obtainable speed. - */ -public class InterferenceLimitedInterface extends NetworkInterface { - protected int currentTransmitSpeed; - protected int numberOfTransmissions; - - public InterferenceLimitedInterface(Settings s) { - super(s); - this.currentTransmitSpeed = 0; - this.numberOfTransmissions = 0; - } - - /** - * Copy constructor - * @param ni the copied network interface object - */ - public InterferenceLimitedInterface(InterferenceLimitedInterface ni) { - super(ni); - this.transmitRange = ni.transmitRange; - this.transmitSpeed = ni.transmitSpeed; - this.currentTransmitSpeed = 0; - this.numberOfTransmissions = 0; - } - - - public NetworkInterface replicate() { - return new InterferenceLimitedInterface(this); - } - - /** - * Returns the transmit speed of this network layer - * @return the transmit speed - */ - @Override - public int getTransmitSpeed(NetworkInterface ni) { - return this.currentTransmitSpeed; - } - - /** - * Tries to connect this host to another host. The other host must be - * active and within range of this host for the connection to succeed. - * @param anotherInterface The host to connect to - */ - public void connect(NetworkInterface anotherInterface) { - if (isScanning() - && anotherInterface.getHost().isRadioActive() - && isWithinRange(anotherInterface) - && !isConnected(anotherInterface) - && (this != anotherInterface)) { - // new contact within range - - Connection con = new VBRConnection(this.host, this, - anotherInterface.getHost(), anotherInterface); - connect(con, anotherInterface); - } - } - - /** - * Updates the state of current connections (i.e., tears down connections - * that are out of range). - */ - public void update() { - if (optimizer == null) { - return; /* nothing to do */ - } - - // First break the old ones - optimizer.updateLocation(this); - for (int i=0; i interfaces = - optimizer.getNearInterfaces(this); - for (NetworkInterface i : interfaces) - connect(i); - - // Find the current number of transmissions - // (to calculate the current transmission speed - numberOfTransmissions = 0; - int numberOfActive = 1; - for (Connection con : this.connections) { - if (con.getMessage() != null) { - numberOfTransmissions++; - } - if (((InterferenceLimitedInterface)con.getOtherInterface(this)). - isTransferring() == true) { - numberOfActive++; - } - } - - int ntrans = numberOfTransmissions; - if ( numberOfTransmissions < 1) ntrans = 1; - if ( numberOfActive <2 ) numberOfActive = 2; - - // Based on the equation of Gupta and Kumar - and the transmission speed - // is divided equally to all the ongoing transmissions - currentTransmitSpeed = (int)Math.floor((double)transmitSpeed / - (Math.sqrt((1.0*numberOfActive) * - Math.log(1.0*numberOfActive))) / - ntrans ); - - for (Connection con : getConnections()) { - con.update(); - } - } - - /** - * Creates a connection to another host. This method does not do any checks - * on whether the other node is in range or active - * @param anotherInterface The interface to create the connection to - */ - public void createConnection(NetworkInterface anotherInterface) { - if (!isConnected(anotherInterface) && (this != anotherInterface)) { - // new contact within range - - Connection con = new VBRConnection(this.host, this, - anotherInterface.getHost(), anotherInterface); - connect(con,anotherInterface); - } - } - - /** - * Returns true if this interface is actually transmitting data - */ - public boolean isTransferring() { - return (numberOfTransmissions > 0); - } - - /** - * Returns a string representation of the object. - * @return a string representation of the object. - */ - public String toString() { - return "InterfaceLimitedInterface " + super.toString(); - } - -} \ No newline at end of file +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package interfaces; + +import java.util.Collection; + +import core.Connection; +import core.NetworkInterface; +import core.Settings; +import core.VBRConnection; + +/** + * A simple Network Interface that provides a variable bit-rate service, where + * the bit-rate depends on the number of other transmitting stations within + * range The current transmit speed is updated only if there are ongoing + * transmissions. The configured transmit speed is the maximum obtainable speed. + */ +public class InterferenceLimitedInterface extends NetworkInterface { + protected int currentTransmitSpeed; + protected int numberOfTransmissions; + + public InterferenceLimitedInterface(Settings s) { + super(s); + this.currentTransmitSpeed = 0; + this.numberOfTransmissions = 0; + } + + /** + * Copy constructor + * @param ni the copied network interface object + */ + public InterferenceLimitedInterface(InterferenceLimitedInterface ni) { + super(ni); + this.transmitRange = ni.transmitRange; + this.transmitSpeed = ni.transmitSpeed; + this.currentTransmitSpeed = 0; + this.numberOfTransmissions = 0; + } + + + public NetworkInterface replicate() { + return new InterferenceLimitedInterface(this); + } + + /** + * Returns the transmit speed of this network layer + * @return the transmit speed + */ + @Override + public int getTransmitSpeed(NetworkInterface ni) { + return this.currentTransmitSpeed; + } + + /** + * Tries to connect this host to another host. The other host must be + * active and within range of this host for the connection to succeed. + * @param anotherInterface The host to connect to + */ + public void connect(NetworkInterface anotherInterface) { + if (isScanning() + && anotherInterface.getHost().isRadioActive() + && isWithinRange(anotherInterface) + && !isConnected(anotherInterface) + && (this != anotherInterface)) { + // new contact within range + + Connection con = new VBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface); + connect(con, anotherInterface); + } + } + + /** + * Updates the state of current connections (i.e., tears down connections + * that are out of range). + */ + public void update() { + if (optimizer == null) { + return; /* nothing to do */ + } + + // First break the old ones + optimizer.updateLocation(this); + for (int i=0; i interfaces = + optimizer.getNearInterfaces(this); + for (NetworkInterface i : interfaces) + connect(i); + + // Find the current number of transmissions + // (to calculate the current transmission speed + numberOfTransmissions = 0; + int numberOfActive = 1; + for (Connection con : this.connections) { + if (con.getMessage() != null) { + numberOfTransmissions++; + } + if (((InterferenceLimitedInterface)con.getOtherInterface(this)). + isTransferring() == true) { + numberOfActive++; + } + } + + int ntrans = numberOfTransmissions; + if ( numberOfTransmissions < 1) ntrans = 1; + if ( numberOfActive <2 ) numberOfActive = 2; + + // Based on the equation of Gupta and Kumar - and the transmission speed + // is divided equally to all the ongoing transmissions + currentTransmitSpeed = (int)Math.floor((double)transmitSpeed / + (Math.sqrt((1.0*numberOfActive) * + Math.log(1.0*numberOfActive))) / + ntrans ); + + for (Connection con : getConnections()) { + con.update(); + } + } + + /** + * Creates a connection to another host. This method does not do any checks + * on whether the other node is in range or active + * @param anotherInterface The interface to create the connection to + */ + public void createConnection(NetworkInterface anotherInterface) { + if (!isConnected(anotherInterface) && (this != anotherInterface)) { + // new contact within range + + Connection con = new VBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface); + connect(con,anotherInterface); + } + } + + /** + * Returns true if this interface is actually transmitting data + */ + public boolean isTransferring() { + return (numberOfTransmissions > 0); + } + + /** + * Returns a string representation of the object. + * @return a string representation of the object. + */ + public String toString() { + return "InterfaceLimitedInterface " + super.toString(); + } + +} diff --git a/interfaces/SimpleBroadcastInterface.java b/interfaces/SimpleBroadcastInterface.java index a1ad967df..1e0b9c597 100644 --- a/interfaces/SimpleBroadcastInterface.java +++ b/interfaces/SimpleBroadcastInterface.java @@ -1,124 +1,124 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package interfaces; - -import java.util.Collection; - -import core.CBRConnection; -import core.Connection; -import core.NetworkInterface; -import core.Settings; - -/** - * A simple Network Interface that provides a constant bit-rate service, where - * one transmission can be on at a time. - */ -public class SimpleBroadcastInterface extends NetworkInterface { - - /** - * Reads the interface settings from the Settings file - */ - public SimpleBroadcastInterface(Settings s) { - super(s); - } - - /** - * Copy constructor - * @param ni the copied network interface object - */ - public SimpleBroadcastInterface(SimpleBroadcastInterface ni) { - super(ni); - } - - public NetworkInterface replicate() { - return new SimpleBroadcastInterface(this); - } - - /** - * Tries to connect this host to another host. The other host must be - * active and within range of this host for the connection to succeed. - * @param anotherInterface The interface to connect to - */ - public void connect(NetworkInterface anotherInterface) { - if (isScanning() - && anotherInterface.getHost().isRadioActive() - && isWithinRange(anotherInterface) - && !isConnected(anotherInterface) - && (this != anotherInterface)) { - // new contact within range - // connection speed is the lower one of the two speeds - int conSpeed = anotherInterface.getTransmitSpeed(this); - if (conSpeed > this.transmitSpeed) { - conSpeed = this.transmitSpeed; - } - - Connection con = new CBRConnection(this.host, this, - anotherInterface.getHost(), anotherInterface, conSpeed); - connect(con,anotherInterface); - } - } - - /** - * Updates the state of current connections (i.e. tears down connections - * that are out of range and creates new ones). - */ - public void update() { - if (optimizer == null) { - return; /* nothing to do */ - } - - // First break the old ones - optimizer.updateLocation(this); - for (int i=0; i interfaces = - optimizer.getNearInterfaces(this); - for (NetworkInterface i : interfaces) { - connect(i); - } - } - - /** - * Creates a connection to another host. This method does not do any checks - * on whether the other node is in range or active - * @param anotherInterface The interface to create the connection to - */ - public void createConnection(NetworkInterface anotherInterface) { - if (!isConnected(anotherInterface) && (this != anotherInterface)) { - // connection speed is the lower one of the two speeds - int conSpeed = anotherInterface.getTransmitSpeed(this); - if (conSpeed > this.transmitSpeed) { - conSpeed = this.transmitSpeed; - } - - Connection con = new CBRConnection(this.host, this, - anotherInterface.getHost(), anotherInterface, conSpeed); - connect(con,anotherInterface); - } - } - - /** - * Returns a string representation of the object. - * @return a string representation of the object. - */ - public String toString() { - return "SimpleBroadcastInterface " + super.toString(); - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package interfaces; + +import java.util.Collection; + +import core.CBRConnection; +import core.Connection; +import core.NetworkInterface; +import core.Settings; + +/** + * A simple Network Interface that provides a constant bit-rate service, where + * one transmission can be on at a time. + */ +public class SimpleBroadcastInterface extends NetworkInterface { + + /** + * Reads the interface settings from the Settings file + */ + public SimpleBroadcastInterface(Settings s) { + super(s); + } + + /** + * Copy constructor + * @param ni the copied network interface object + */ + public SimpleBroadcastInterface(SimpleBroadcastInterface ni) { + super(ni); + } + + public NetworkInterface replicate() { + return new SimpleBroadcastInterface(this); + } + + /** + * Tries to connect this host to another host. The other host must be + * active and within range of this host for the connection to succeed. + * @param anotherInterface The interface to connect to + */ + public void connect(NetworkInterface anotherInterface) { + if (isScanning() + && anotherInterface.getHost().isRadioActive() + && isWithinRange(anotherInterface) + && !isConnected(anotherInterface) + && (this != anotherInterface)) { + // new contact within range + // connection speed is the lower one of the two speeds + int conSpeed = anotherInterface.getTransmitSpeed(this); + if (conSpeed > this.transmitSpeed) { + conSpeed = this.transmitSpeed; + } + + Connection con = new CBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface, conSpeed); + connect(con,anotherInterface); + } + } + + /** + * Updates the state of current connections (i.e. tears down connections + * that are out of range and creates new ones). + */ + public void update() { + if (optimizer == null) { + return; /* nothing to do */ + } + + // First break the old ones + optimizer.updateLocation(this); + for (int i=0; i interfaces = + optimizer.getNearInterfaces(this); + for (NetworkInterface i : interfaces) { + connect(i); + } + } + + /** + * Creates a connection to another host. This method does not do any checks + * on whether the other node is in range or active + * @param anotherInterface The interface to create the connection to + */ + public void createConnection(NetworkInterface anotherInterface) { + if (!isConnected(anotherInterface) && (this != anotherInterface)) { + // connection speed is the lower one of the two speeds + int conSpeed = anotherInterface.getTransmitSpeed(this); + if (conSpeed > this.transmitSpeed) { + conSpeed = this.transmitSpeed; + } + + Connection con = new CBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface, conSpeed); + connect(con,anotherInterface); + } + } + + /** + * Returns a string representation of the object. + * @return a string representation of the object. + */ + public String toString() { + return "SimpleBroadcastInterface " + super.toString(); + } + +} diff --git a/movement/BusControlSystem.java b/movement/BusControlSystem.java index 9e94031ff..a94ea718e 100644 --- a/movement/BusControlSystem.java +++ b/movement/BusControlSystem.java @@ -1,144 +1,144 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - -import movement.map.SimMap; -import core.Coord; -import core.DTNSim; - -/** - * This class controls busses and passengers that can use the bus. - * There can be many bus BusControlSystems, but a bus or passenger can only - * belong to one system. - * - * @author Frans Ekman - */ -public class BusControlSystem { - public static final String BUS_CONTROL_SYSTEM_NR = "busControlSystemNr"; - - private static HashMap systems; - - private HashMap busses; - private HashMap travellers; - private List busStops; - - private SimMap simMap; - - static { - DTNSim.registerForReset(BusControlSystem.class.getCanonicalName()); - reset(); - } - - /** - * Creates a new instance of BusControlSystem without any travelers or - * busses - * @param systemID The unique ID of this system. - */ - private BusControlSystem(int systemID) { - busses = new HashMap(); - travellers = new HashMap(); - } - - public static void reset() { - systems = new HashMap(); - } - - /** - * Called by busses belonging to this system every time the bus has stopped. - * It calls every passengers enterBus() method so that the passengers can - * enter the bus if they want to. - * @param busID Unique identifier of the bus - * @param busStop Coordinates of the bus stop - * @param nextPath The path to the next stop - */ - public void busHasStopped(int busID, Coord busStop, Path nextPath) { - Iterator iterator = travellers.values(). - iterator(); - while (iterator.hasNext()) { - BusTravellerMovement traveller = (BusTravellerMovement)iterator. - next(); - if (traveller.getLocation() != null) { - if ((traveller.getLocation()).equals(busStop)) { - if (traveller.getState() == BusTravellerMovement. - STATE_WAITING_FOR_BUS) { - Path path = new Path(nextPath); - traveller.enterBus(path); - } - } - } - } - } - - /** - * Returns a reference to a BusControlSystem with ID provided as parameter. - * If a system does not already exist with the requested ID, a new one is - * created. - * @param systemID unique ID of the system - * @return The bus control system with the provided ID - */ - public static BusControlSystem getBusControlSystem(int systemID) { - Integer id = new Integer(systemID); - - if (systems.containsKey(id)) { - return systems.get(id); - } else { - BusControlSystem bcs = new BusControlSystem(systemID); - systems.put(id, bcs); - return bcs; - } - } - - /** - * Registers a bus to be part of a bus control system - * @param bus The bus to register - */ - public void registerBus(BusMovement bus) { - busses.put(bus.getID(), bus); - } - - /** - * Registers a traveller/passenger to be part of a bus control system - * @param traveller The traveller to register - */ - public void registerTraveller(BusTravellerMovement traveller) { - travellers.put(traveller.getID(), traveller); - } - - /** - * Provide the system with the map - * @param map - */ - public void setMap(SimMap map) { - this.simMap = map; - } - - /** - * Get the underlying map of the system - * @return The map - */ - public SimMap getMap() { - return this.simMap; - } - - /** - * @return A list of all bus stops belonging to this system - */ - public List getBusStops() { - return busStops; - } - - /** - * Set the bus stops that belong to this system - * @param busStops - */ - public void setBusStops(List busStops) { - this.busStops = busStops; - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import movement.map.SimMap; +import core.Coord; +import core.DTNSim; + +/** + * This class controls busses and passengers that can use the bus. + * There can be many bus BusControlSystems, but a bus or passenger can only + * belong to one system. + * + * @author Frans Ekman + */ +public class BusControlSystem { + public static final String BUS_CONTROL_SYSTEM_NR = "busControlSystemNr"; + + private static HashMap systems; + + private HashMap busses; + private HashMap travellers; + private List busStops; + + private SimMap simMap; + + static { + DTNSim.registerForReset(BusControlSystem.class.getCanonicalName()); + reset(); + } + + /** + * Creates a new instance of BusControlSystem without any travelers or + * busses + * @param systemID The unique ID of this system. + */ + private BusControlSystem(int systemID) { + busses = new HashMap(); + travellers = new HashMap(); + } + + public static void reset() { + systems = new HashMap(); + } + + /** + * Called by busses belonging to this system every time the bus has stopped. + * It calls every passengers enterBus() method so that the passengers can + * enter the bus if they want to. + * @param busID Unique identifier of the bus + * @param busStop Coordinates of the bus stop + * @param nextPath The path to the next stop + */ + public void busHasStopped(int busID, Coord busStop, Path nextPath) { + Iterator iterator = travellers.values(). + iterator(); + while (iterator.hasNext()) { + BusTravellerMovement traveller = (BusTravellerMovement)iterator. + next(); + if (traveller.getLocation() != null) { + if ((traveller.getLocation()).equals(busStop)) { + if (traveller.getState() == BusTravellerMovement. + STATE_WAITING_FOR_BUS) { + Path path = new Path(nextPath); + traveller.enterBus(path); + } + } + } + } + } + + /** + * Returns a reference to a BusControlSystem with ID provided as parameter. + * If a system does not already exist with the requested ID, a new one is + * created. + * @param systemID unique ID of the system + * @return The bus control system with the provided ID + */ + public static BusControlSystem getBusControlSystem(int systemID) { + Integer id = new Integer(systemID); + + if (systems.containsKey(id)) { + return systems.get(id); + } else { + BusControlSystem bcs = new BusControlSystem(systemID); + systems.put(id, bcs); + return bcs; + } + } + + /** + * Registers a bus to be part of a bus control system + * @param bus The bus to register + */ + public void registerBus(BusMovement bus) { + busses.put(bus.getID(), bus); + } + + /** + * Registers a traveller/passenger to be part of a bus control system + * @param traveller The traveller to register + */ + public void registerTraveller(BusTravellerMovement traveller) { + travellers.put(traveller.getID(), traveller); + } + + /** + * Provide the system with the map + * @param map + */ + public void setMap(SimMap map) { + this.simMap = map; + } + + /** + * Get the underlying map of the system + * @return The map + */ + public SimMap getMap() { + return this.simMap; + } + + /** + * @return A list of all bus stops belonging to this system + */ + public List getBusStops() { + return busStops; + } + + /** + * Set the bus stops that belong to this system + * @param busStops + */ + public void setBusStops(List busStops) { + this.busStops = busStops; + } + +} diff --git a/movement/BusMovement.java b/movement/BusMovement.java index d8a63a481..f93bc01cd 100644 --- a/movement/BusMovement.java +++ b/movement/BusMovement.java @@ -1,89 +1,89 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import java.util.LinkedList; -import java.util.List; - -import movement.map.MapNode; -import core.Coord; -import core.Settings; - -/** - * This class controls the movement of busses. It informs the bus control system - * the bus is registered with every time the bus stops. - * - * @author Frans Ekman - */ -public class BusMovement extends MapRouteMovement { - - private BusControlSystem controlSystem; - private int id; - private static int nextID = 0; - private boolean startMode; - private List stops; - - /** - * Creates a new instance of BusMovement - * @param settings - */ - public BusMovement(Settings settings) { - super(settings); - int bcs = settings.getInt(BusControlSystem.BUS_CONTROL_SYSTEM_NR); - controlSystem = BusControlSystem.getBusControlSystem(bcs); - controlSystem.setMap(super.getMap()); - this.id = nextID++; - controlSystem.registerBus(this); - startMode = true; - stops = new LinkedList(); - List stopNodes = super.getStops(); - for (MapNode node : stopNodes) { - stops.add(node.getLocation().clone()); - } - controlSystem.setBusStops(stops); - } - - /** - * Create a new instance from a prototype - * @param proto - */ - public BusMovement(BusMovement proto) { - super(proto); - this.controlSystem = proto.controlSystem; - this.id = nextID++; - controlSystem.registerBus(this); - startMode = true; - } - - @Override - public Coord getInitialLocation() { - return (super.getInitialLocation()).clone(); - } - - @Override - public Path getPath() { - Coord lastLocation = (super.getLastLocation()).clone(); - Path path = super.getPath(); - if (!startMode) { - controlSystem.busHasStopped(id, lastLocation, path); - } - startMode = false; - return path; - } - - @Override - public BusMovement replicate() { - return new BusMovement(this); - } - - /** - * Returns unique ID of the bus - * @return unique ID of the bus - */ - public int getID() { - return id; - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.LinkedList; +import java.util.List; + +import movement.map.MapNode; +import core.Coord; +import core.Settings; + +/** + * This class controls the movement of busses. It informs the bus control system + * the bus is registered with every time the bus stops. + * + * @author Frans Ekman + */ +public class BusMovement extends MapRouteMovement { + + private BusControlSystem controlSystem; + private int id; + private static int nextID = 0; + private boolean startMode; + private List stops; + + /** + * Creates a new instance of BusMovement + * @param settings + */ + public BusMovement(Settings settings) { + super(settings); + int bcs = settings.getInt(BusControlSystem.BUS_CONTROL_SYSTEM_NR); + controlSystem = BusControlSystem.getBusControlSystem(bcs); + controlSystem.setMap(super.getMap()); + this.id = nextID++; + controlSystem.registerBus(this); + startMode = true; + stops = new LinkedList(); + List stopNodes = super.getStops(); + for (MapNode node : stopNodes) { + stops.add(node.getLocation().clone()); + } + controlSystem.setBusStops(stops); + } + + /** + * Create a new instance from a prototype + * @param proto + */ + public BusMovement(BusMovement proto) { + super(proto); + this.controlSystem = proto.controlSystem; + this.id = nextID++; + controlSystem.registerBus(this); + startMode = true; + } + + @Override + public Coord getInitialLocation() { + return (super.getInitialLocation()).clone(); + } + + @Override + public Path getPath() { + Coord lastLocation = (super.getLastLocation()).clone(); + Path path = super.getPath(); + if (!startMode) { + controlSystem.busHasStopped(id, lastLocation, path); + } + startMode = false; + return path; + } + + @Override + public BusMovement replicate() { + return new BusMovement(this); + } + + /** + * Returns unique ID of the bus + * @return unique ID of the bus + */ + public int getID() { + return id; + } + +} diff --git a/movement/BusTravellerMovement.java b/movement/BusTravellerMovement.java index 51b8b8bdc..0f8482ac1 100644 --- a/movement/BusTravellerMovement.java +++ b/movement/BusTravellerMovement.java @@ -1,357 +1,357 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import java.util.List; -import java.util.Random; - -import movement.map.DijkstraPathFinder; -import movement.map.MapNode; -import movement.map.SimMap; -import core.Coord; -import core.Settings; - -/** - * - * This class controls the movement of bus travellers. A bus traveller belongs - * to a bus control system. A bus traveller has a destination and a start - * location. If the direct path to the destination is longer than the path the - * node would have to walk if it would take the bus, the node uses the bus. If - * the destination is not provided, the node will pass a random number of stops - * determined by Markov chains (defined in settings). - * - * @author Frans Ekman - * - */ -public class BusTravellerMovement extends MapBasedMovement implements - SwitchableMovement, TransportMovement { - - public static final String PROBABILITIES_STRING = "probs"; - public static final String PROBABILITY_TAKE_OTHER_BUS = "probTakeOtherBus"; - - public static final int STATE_WAITING_FOR_BUS = 0; - public static final int STATE_DECIDED_TO_ENTER_A_BUS = 1; - public static final int STATE_TRAVELLING_ON_BUS = 2; - public static final int STATE_WALKING_ELSEWHERE = 3; - - private int state; - private Path nextPath; - private Coord location; - private Coord latestBusStop; - private BusControlSystem controlSystem; - private int id; - private ContinueBusTripDecider cbtd; - private double[] probabilities; - private double probTakeOtherBus; - private DijkstraPathFinder pathFinder; - - private Coord startBusStop; - private Coord endBusStop; - - private boolean takeBus; - - private static int nextID = 0; - - /** - * Creates a BusTravellerModel - * @param settings - */ - public BusTravellerMovement(Settings settings) { - super(settings); - int bcs = settings.getInt(BusControlSystem.BUS_CONTROL_SYSTEM_NR); - controlSystem = BusControlSystem.getBusControlSystem(bcs); - id = nextID++; - controlSystem.registerTraveller(this); - nextPath = new Path(); - state = STATE_WALKING_ELSEWHERE; - if (settings.contains(PROBABILITIES_STRING)) { - probabilities = settings.getCsvDoubles(PROBABILITIES_STRING); - } - if (settings.contains(PROBABILITY_TAKE_OTHER_BUS)) { - probTakeOtherBus = settings.getDouble(PROBABILITY_TAKE_OTHER_BUS); - } - cbtd = new ContinueBusTripDecider(rng, probabilities); - pathFinder = new DijkstraPathFinder(null); - takeBus = true; - } - - /** - * Creates a BusTravellerModel from a prototype - * @param proto - */ - public BusTravellerMovement(BusTravellerMovement proto) { - super(proto); - state = proto.state; - controlSystem = proto.controlSystem; - if (proto.location != null) { - location = proto.location.clone(); - } - nextPath = proto.nextPath; - id = nextID++; - controlSystem.registerTraveller(this); - probabilities = proto.probabilities; - cbtd = new ContinueBusTripDecider(rng, probabilities); - pathFinder = proto.pathFinder; - this.probTakeOtherBus = proto.probTakeOtherBus; - takeBus = true; - } - - @Override - public Coord getInitialLocation() { - - MapNode[] mapNodes = (MapNode[])getMap().getNodes(). - toArray(new MapNode[0]); - int index = rng.nextInt(mapNodes.length - 1); - location = mapNodes[index].getLocation().clone(); - - List allStops = controlSystem.getBusStops(); - Coord closestToNode = getClosestCoordinate(allStops, location.clone()); - latestBusStop = closestToNode.clone(); - - return location.clone(); - } - - @Override - public Path getPath() { - if (!takeBus) { - return null; - } - if (state == STATE_WAITING_FOR_BUS) { - return null; - } else if (state == STATE_DECIDED_TO_ENTER_A_BUS) { - state = STATE_TRAVELLING_ON_BUS; - List coords = nextPath.getCoords(); - location = (coords.get(coords.size() - 1)).clone(); - return nextPath; - } else if (state == STATE_WALKING_ELSEWHERE) { - // Try to find back to the bus stop - SimMap map = controlSystem.getMap(); - if (map == null) { - return null; - } - MapNode thisNode = map.getNodeByCoord(location); - MapNode destinationNode = map.getNodeByCoord(latestBusStop); - List nodes = pathFinder.getShortestPath(thisNode, - destinationNode); - Path path = new Path(generateSpeed()); - for (MapNode node : nodes) { - path.addWaypoint(node.getLocation()); - } - location = latestBusStop.clone(); - return path; - } - - return null; - } - - /** - * Switches state between getPath() calls - * @return Always 0 - */ - protected double generateWaitTime() { - if (state == STATE_WALKING_ELSEWHERE) { - if (location.equals(latestBusStop)) { - state = STATE_WAITING_FOR_BUS; - } - } - if (state == STATE_TRAVELLING_ON_BUS) { - state = STATE_WAITING_FOR_BUS; - } - return 0; - } - - @Override - public MapBasedMovement replicate() { - return new BusTravellerMovement(this); - } - - public int getState() { - return state; - } - - /** - * Get the location where the bus is located when it has moved its path - * @return The end point of the last path returned - */ - public Coord getLocation() { - if (location == null) { - return null; - } - return location.clone(); - } - - /** - * Notifies the node at the bus stop that a bus is there. Nodes inside - * busses are also notified. - * @param nextPath The next path the bus is going to take - */ - public void enterBus(Path nextPath) { - - if (startBusStop != null && endBusStop != null) { - if (location.equals(endBusStop)) { - state = STATE_WALKING_ELSEWHERE; - latestBusStop = location.clone(); - } else { - state = STATE_DECIDED_TO_ENTER_A_BUS; - this.nextPath = nextPath; - } - return; - } - - if (!cbtd.continueTrip()) { - state = STATE_WAITING_FOR_BUS; - this.nextPath = null; - /* It might decide not to start walking somewhere and wait - for the next bus */ - if (rng.nextDouble() > probTakeOtherBus) { - state = STATE_WALKING_ELSEWHERE; - latestBusStop = location.clone(); - } - } else { - state = STATE_DECIDED_TO_ENTER_A_BUS; - this.nextPath = nextPath; - } - } - - public int getID() { - return id; - } - - - /** - * Small class to help nodes decide if they should continue the bus trip. - * Keeps the state of nodes, i.e. how many stops they have passed so far. - * Markov chain probabilities for the decisions. - * - * NOT USED BY THE WORKING DAY MOVEMENT MODEL - * - * @author Frans Ekman - */ - class ContinueBusTripDecider { - - private double[] probabilities; // Probability to travel with bus - private int state; - private Random rng; - - public ContinueBusTripDecider(Random rng, double[] probabilities) { - this.rng = rng; - this.probabilities = probabilities; - state = 0; - } - - /** - * - * @return true if node should continue - */ - public boolean continueTrip() { - double rand = rng.nextDouble(); - if (rand < probabilities[state]) { - incState(); - return true; - } else { - resetState(); - return false; - } - } - - /** - * Call when a stop has been passed - */ - private void incState() { - if (state < probabilities.length - 1) { - state++; - } - } - - /** - * Call when node has finished it's trip - */ - private void resetState() { - state = 0; - } - } - - /** - * Help method to find the closest coordinate from a list of coordinates, - * to a specific location - * @param allCoords list of coordinates to compare - * @param coord destination node - * @return closest to the destination - */ - private static Coord getClosestCoordinate(List allCoords, - Coord coord) { - Coord closestCoord = null; - double minDistance = Double.POSITIVE_INFINITY; - for (Coord temp : allCoords) { - double distance = temp.distance(coord); - if (distance < minDistance) { - minDistance = distance; - closestCoord = temp; - } - } - return closestCoord.clone(); - } - - /** - * Sets the next route for the traveller, so that it can decide wether it - * should take the bus or not. - * @param nodeLocation - * @param nodeDestination - */ - public void setNextRoute(Coord nodeLocation, Coord nodeDestination) { - - // Find closest stops to current location and destination - List allStops = controlSystem.getBusStops(); - - Coord closestToNode = getClosestCoordinate(allStops, nodeLocation); - Coord closestToDestination = getClosestCoordinate(allStops, - nodeDestination); - - // Check if it is shorter to walk than take the bus - double directDistance = nodeLocation.distance(nodeDestination); - double busDistance = nodeLocation.distance(closestToNode) + - nodeDestination.distance(closestToDestination); - - if (directDistance < busDistance) { - takeBus = false; - } else { - takeBus = true; - } - - this.startBusStop = closestToNode; - this.endBusStop = closestToDestination; - this.latestBusStop = startBusStop.clone(); - } - - /** - * @see SwitchableMovement - */ - public Coord getLastLocation() { - return location.clone(); - } - - /** - * @see SwitchableMovement - */ - public void setLocation(Coord lastWaypoint) { - location = lastWaypoint.clone(); - } - - /** - * @see SwitchableMovement - */ - public boolean isReady() { - if (state == STATE_WALKING_ELSEWHERE) { - return true; - } else { - return false; - } - } - - public static void reset() { - nextID = 0; - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.List; +import java.util.Random; + +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import movement.map.SimMap; +import core.Coord; +import core.Settings; + +/** + * + * This class controls the movement of bus travellers. A bus traveller belongs + * to a bus control system. A bus traveller has a destination and a start + * location. If the direct path to the destination is longer than the path the + * node would have to walk if it would take the bus, the node uses the bus. If + * the destination is not provided, the node will pass a random number of stops + * determined by Markov chains (defined in settings). + * + * @author Frans Ekman + * + */ +public class BusTravellerMovement extends MapBasedMovement implements + SwitchableMovement, TransportMovement { + + public static final String PROBABILITIES_STRING = "probs"; + public static final String PROBABILITY_TAKE_OTHER_BUS = "probTakeOtherBus"; + + public static final int STATE_WAITING_FOR_BUS = 0; + public static final int STATE_DECIDED_TO_ENTER_A_BUS = 1; + public static final int STATE_TRAVELLING_ON_BUS = 2; + public static final int STATE_WALKING_ELSEWHERE = 3; + + private int state; + private Path nextPath; + private Coord location; + private Coord latestBusStop; + private BusControlSystem controlSystem; + private int id; + private ContinueBusTripDecider cbtd; + private double[] probabilities; + private double probTakeOtherBus; + private DijkstraPathFinder pathFinder; + + private Coord startBusStop; + private Coord endBusStop; + + private boolean takeBus; + + private static int nextID = 0; + + /** + * Creates a BusTravellerModel + * @param settings + */ + public BusTravellerMovement(Settings settings) { + super(settings); + int bcs = settings.getInt(BusControlSystem.BUS_CONTROL_SYSTEM_NR); + controlSystem = BusControlSystem.getBusControlSystem(bcs); + id = nextID++; + controlSystem.registerTraveller(this); + nextPath = new Path(); + state = STATE_WALKING_ELSEWHERE; + if (settings.contains(PROBABILITIES_STRING)) { + probabilities = settings.getCsvDoubles(PROBABILITIES_STRING); + } + if (settings.contains(PROBABILITY_TAKE_OTHER_BUS)) { + probTakeOtherBus = settings.getDouble(PROBABILITY_TAKE_OTHER_BUS); + } + cbtd = new ContinueBusTripDecider(rng, probabilities); + pathFinder = new DijkstraPathFinder(null); + takeBus = true; + } + + /** + * Creates a BusTravellerModel from a prototype + * @param proto + */ + public BusTravellerMovement(BusTravellerMovement proto) { + super(proto); + state = proto.state; + controlSystem = proto.controlSystem; + if (proto.location != null) { + location = proto.location.clone(); + } + nextPath = proto.nextPath; + id = nextID++; + controlSystem.registerTraveller(this); + probabilities = proto.probabilities; + cbtd = new ContinueBusTripDecider(rng, probabilities); + pathFinder = proto.pathFinder; + this.probTakeOtherBus = proto.probTakeOtherBus; + takeBus = true; + } + + @Override + public Coord getInitialLocation() { + + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int index = rng.nextInt(mapNodes.length - 1); + location = mapNodes[index].getLocation().clone(); + + List allStops = controlSystem.getBusStops(); + Coord closestToNode = getClosestCoordinate(allStops, location.clone()); + latestBusStop = closestToNode.clone(); + + return location.clone(); + } + + @Override + public Path getPath() { + if (!takeBus) { + return null; + } + if (state == STATE_WAITING_FOR_BUS) { + return null; + } else if (state == STATE_DECIDED_TO_ENTER_A_BUS) { + state = STATE_TRAVELLING_ON_BUS; + List coords = nextPath.getCoords(); + location = (coords.get(coords.size() - 1)).clone(); + return nextPath; + } else if (state == STATE_WALKING_ELSEWHERE) { + // Try to find back to the bus stop + SimMap map = controlSystem.getMap(); + if (map == null) { + return null; + } + MapNode thisNode = map.getNodeByCoord(location); + MapNode destinationNode = map.getNodeByCoord(latestBusStop); + List nodes = pathFinder.getShortestPath(thisNode, + destinationNode); + Path path = new Path(generateSpeed()); + for (MapNode node : nodes) { + path.addWaypoint(node.getLocation()); + } + location = latestBusStop.clone(); + return path; + } + + return null; + } + + /** + * Switches state between getPath() calls + * @return Always 0 + */ + protected double generateWaitTime() { + if (state == STATE_WALKING_ELSEWHERE) { + if (location.equals(latestBusStop)) { + state = STATE_WAITING_FOR_BUS; + } + } + if (state == STATE_TRAVELLING_ON_BUS) { + state = STATE_WAITING_FOR_BUS; + } + return 0; + } + + @Override + public MapBasedMovement replicate() { + return new BusTravellerMovement(this); + } + + public int getState() { + return state; + } + + /** + * Get the location where the bus is located when it has moved its path + * @return The end point of the last path returned + */ + public Coord getLocation() { + if (location == null) { + return null; + } + return location.clone(); + } + + /** + * Notifies the node at the bus stop that a bus is there. Nodes inside + * busses are also notified. + * @param nextPath The next path the bus is going to take + */ + public void enterBus(Path nextPath) { + + if (startBusStop != null && endBusStop != null) { + if (location.equals(endBusStop)) { + state = STATE_WALKING_ELSEWHERE; + latestBusStop = location.clone(); + } else { + state = STATE_DECIDED_TO_ENTER_A_BUS; + this.nextPath = nextPath; + } + return; + } + + if (!cbtd.continueTrip()) { + state = STATE_WAITING_FOR_BUS; + this.nextPath = null; + /* It might decide not to start walking somewhere and wait + for the next bus */ + if (rng.nextDouble() > probTakeOtherBus) { + state = STATE_WALKING_ELSEWHERE; + latestBusStop = location.clone(); + } + } else { + state = STATE_DECIDED_TO_ENTER_A_BUS; + this.nextPath = nextPath; + } + } + + public int getID() { + return id; + } + + + /** + * Small class to help nodes decide if they should continue the bus trip. + * Keeps the state of nodes, i.e. how many stops they have passed so far. + * Markov chain probabilities for the decisions. + * + * NOT USED BY THE WORKING DAY MOVEMENT MODEL + * + * @author Frans Ekman + */ + class ContinueBusTripDecider { + + private double[] probabilities; // Probability to travel with bus + private int state; + private Random rng; + + public ContinueBusTripDecider(Random rng, double[] probabilities) { + this.rng = rng; + this.probabilities = probabilities; + state = 0; + } + + /** + * + * @return true if node should continue + */ + public boolean continueTrip() { + double rand = rng.nextDouble(); + if (rand < probabilities[state]) { + incState(); + return true; + } else { + resetState(); + return false; + } + } + + /** + * Call when a stop has been passed + */ + private void incState() { + if (state < probabilities.length - 1) { + state++; + } + } + + /** + * Call when node has finished it's trip + */ + private void resetState() { + state = 0; + } + } + + /** + * Help method to find the closest coordinate from a list of coordinates, + * to a specific location + * @param allCoords list of coordinates to compare + * @param coord destination node + * @return closest to the destination + */ + private static Coord getClosestCoordinate(List allCoords, + Coord coord) { + Coord closestCoord = null; + double minDistance = Double.POSITIVE_INFINITY; + for (Coord temp : allCoords) { + double distance = temp.distance(coord); + if (distance < minDistance) { + minDistance = distance; + closestCoord = temp; + } + } + return closestCoord.clone(); + } + + /** + * Sets the next route for the traveller, so that it can decide wether it + * should take the bus or not. + * @param nodeLocation + * @param nodeDestination + */ + public void setNextRoute(Coord nodeLocation, Coord nodeDestination) { + + // Find closest stops to current location and destination + List allStops = controlSystem.getBusStops(); + + Coord closestToNode = getClosestCoordinate(allStops, nodeLocation); + Coord closestToDestination = getClosestCoordinate(allStops, + nodeDestination); + + // Check if it is shorter to walk than take the bus + double directDistance = nodeLocation.distance(nodeDestination); + double busDistance = nodeLocation.distance(closestToNode) + + nodeDestination.distance(closestToDestination); + + if (directDistance < busDistance) { + takeBus = false; + } else { + takeBus = true; + } + + this.startBusStop = closestToNode; + this.endBusStop = closestToDestination; + this.latestBusStop = startBusStop.clone(); + } + + /** + * @see SwitchableMovement + */ + public Coord getLastLocation() { + return location.clone(); + } + + /** + * @see SwitchableMovement + */ + public void setLocation(Coord lastWaypoint) { + location = lastWaypoint.clone(); + } + + /** + * @see SwitchableMovement + */ + public boolean isReady() { + if (state == STATE_WALKING_ELSEWHERE) { + return true; + } else { + return false; + } + } + + public static void reset() { + nextID = 0; + } + +} diff --git a/movement/CarMovement.java b/movement/CarMovement.java index 19518ef33..951525c2a 100644 --- a/movement/CarMovement.java +++ b/movement/CarMovement.java @@ -1,80 +1,80 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import java.util.List; - -import movement.map.DijkstraPathFinder; -import movement.map.MapNode; -import core.Coord; -import core.Settings; - -/** - * The CarMovement class representing the car movement submodel - * - * @author Frans Ekman - */ -public class CarMovement extends MapBasedMovement implements - SwitchableMovement, TransportMovement { - - private Coord from; - private Coord to; - - private DijkstraPathFinder pathFinder; - - /** - * Car movement constructor - * @param settings - */ - public CarMovement(Settings settings) { - super(settings); - pathFinder = new DijkstraPathFinder(getOkMapNodeTypes()); - } - - /** - * Construct a new CarMovement instance from a prototype - * @param proto - */ - public CarMovement(CarMovement proto) { - super(proto); - this.pathFinder = proto.pathFinder; - } - - /** - * Sets the next route to be taken - * @param nodeLocation - * @param nodeDestination - */ - public void setNextRoute(Coord nodeLocation, Coord nodeDestination) { - from = nodeLocation.clone(); - to = nodeDestination.clone(); - } - - @Override - public Path getPath() { - Path path = new Path(generateSpeed()); - - MapNode fromNode = getMap().getNodeByCoord(from); - MapNode toNode = getMap().getNodeByCoord(to); - - List nodePath = pathFinder.getShortestPath(fromNode, toNode); - - for (MapNode node : nodePath) { // create a Path from the shortest path - path.addWaypoint(node.getLocation()); - } - - lastMapNode = toNode; - - return path; - } - - /** - * @see SwitchableMovement - * @return true - */ - public boolean isReady() { - return true; - } -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.List; + +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import core.Coord; +import core.Settings; + +/** + * The CarMovement class representing the car movement submodel + * + * @author Frans Ekman + */ +public class CarMovement extends MapBasedMovement implements + SwitchableMovement, TransportMovement { + + private Coord from; + private Coord to; + + private DijkstraPathFinder pathFinder; + + /** + * Car movement constructor + * @param settings + */ + public CarMovement(Settings settings) { + super(settings); + pathFinder = new DijkstraPathFinder(getOkMapNodeTypes()); + } + + /** + * Construct a new CarMovement instance from a prototype + * @param proto + */ + public CarMovement(CarMovement proto) { + super(proto); + this.pathFinder = proto.pathFinder; + } + + /** + * Sets the next route to be taken + * @param nodeLocation + * @param nodeDestination + */ + public void setNextRoute(Coord nodeLocation, Coord nodeDestination) { + from = nodeLocation.clone(); + to = nodeDestination.clone(); + } + + @Override + public Path getPath() { + Path path = new Path(generateSpeed()); + + MapNode fromNode = getMap().getNodeByCoord(from); + MapNode toNode = getMap().getNodeByCoord(to); + + List nodePath = pathFinder.getShortestPath(fromNode, toNode); + + for (MapNode node : nodePath) { // create a Path from the shortest path + path.addWaypoint(node.getLocation()); + } + + lastMapNode = toNode; + + return path; + } + + /** + * @see SwitchableMovement + * @return true + */ + public boolean isReady() { + return true; + } +} diff --git a/movement/ClusterMovement.java b/movement/ClusterMovement.java index c4d666303..aa9eb22c5 100644 --- a/movement/ClusterMovement.java +++ b/movement/ClusterMovement.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -/** +/** * Random waypoint movement where the coordinates are restricted to circular * area defined by a central point and range. * @author teemuk @@ -18,13 +18,13 @@ public class ClusterMovement extends RandomWaypoint { public static final String CLUSTER_RANGE = "clusterRange"; /** Center point of the cluster */ public static final String CLUSTER_CENTER = "clusterCenter"; - + private int p_x_center = 100, p_y_center = 100; private double p_range = 100.0; - + public ClusterMovement(Settings s) { super(s); - + if (s.contains(CLUSTER_RANGE)){ this.p_range = s.getDouble(CLUSTER_RANGE); } @@ -34,14 +34,14 @@ public ClusterMovement(Settings s) { this.p_y_center = center[1]; } } - + private ClusterMovement(ClusterMovement cmv) { super(cmv); this.p_range = cmv.p_range; this.p_x_center = cmv.p_x_center; this.p_y_center = cmv.p_y_center; } - + @Override protected Coord randomCoord() { double x = (rng.nextDouble()*2 - 1)*this.p_range; @@ -54,7 +54,7 @@ protected Coord randomCoord() { y += this.p_y_center; return new Coord(x,y); } - + @Override public int getMaxX() { return (int)Math.ceil(this.p_x_center + this.p_range); @@ -64,7 +64,7 @@ public int getMaxX() { public int getMaxY() { return (int)Math.ceil(this.p_y_center + this.p_range); } - + @Override public ClusterMovement replicate() { return new ClusterMovement(this); diff --git a/movement/EveningActivityControlSystem.java b/movement/EveningActivityControlSystem.java index f8fc1042e..bc003a610 100644 --- a/movement/EveningActivityControlSystem.java +++ b/movement/EveningActivityControlSystem.java @@ -1,140 +1,140 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import java.util.HashMap; -import java.util.List; -import java.util.Random; - -import core.Coord; -import core.DTNSim; - -/** - * This class controls the group mobility of the people meeting their friends in - * the evening - * - * @author Frans Ekman - */ -public class EveningActivityControlSystem { - - private HashMap eveningActivityNodes; - private List meetingSpots; - private EveningTrip[] nextTrips; - - private Random rng; - - private static HashMap - controlSystems; - - static { - DTNSim.registerForReset(EveningActivityControlSystem.class. - getCanonicalName()); - reset(); - } - - /** - * Creates a new instance of EveningActivityControlSystem without any nodes - * or meeting spots, with the ID given as parameter - * @param id - */ - private EveningActivityControlSystem(int id) { - eveningActivityNodes = new HashMap(); - } - - public static void reset() { - controlSystems = new HashMap(); - } - - /** - * Register a evening activity node with the system - * @param eveningMovement activity movement - */ - public void addEveningActivityNode(EveningActivityMovement eveningMovement) { - eveningActivityNodes.put(new Integer(eveningMovement.getID()), - eveningMovement); - } - - /** - * Sets the meeting locations the nodes can choose among - * @param meetingSpots - */ - public void setMeetingSpots(List meetingSpots) { - this.meetingSpots = meetingSpots; - this.nextTrips = new EveningTrip[meetingSpots.size()]; - } - - /** - * This method gets the instruction for a node, i.e. When/where and with - * whom to go. - * @param eveningActivityNodeID unique ID of the node - * @return Instructions object - */ - public EveningTrip getEveningInstructions(int eveningActivityNodeID) { - EveningActivityMovement eveningMovement = eveningActivityNodes.get( - new Integer(eveningActivityNodeID)); - if (eveningMovement != null) { - int index = eveningActivityNodeID % meetingSpots.size(); - if (nextTrips[index] == null) { - int nrOfEveningMovementNodes = (int)(eveningMovement. - getMinGroupSize() + - (double)(eveningMovement.getMaxGroupSize() - - eveningMovement.getMinGroupSize()) * - rng.nextDouble()); - Coord loc = meetingSpots.get(index).clone(); - nextTrips[index] = new EveningTrip(nrOfEveningMovementNodes, - loc); - } - nextTrips[index].addNode(eveningMovement); - if (nextTrips[index].isFull()) { - EveningTrip temp = nextTrips[index]; - nextTrips[index] = null; - return temp; - } else { - return nextTrips[index]; - } - } - return null; - } - - /** - * Get the meeting spot for the node - * @param id - * @return Coordinates of the spot - */ - public Coord getMeetingSpotForID(int id) { - int index = id % meetingSpots.size(); - Coord loc = meetingSpots.get(index).clone(); - return loc; - } - - - /** - * Sets the random number generator to be used - * @param rand - */ - public void setRandomNumberGenerator(Random rand) { - this.rng = rand; - } - - /** - * Returns a reference to a EveningActivityControlSystem with ID provided as - * parameter. If a system does not already exist with the requested ID, a - * new one is created. - * @param id unique ID of the EveningActivityControlSystem - * @return The EveningActivityControlSystem with the provided ID - */ - public static EveningActivityControlSystem getEveningActivityControlSystem( - int id) { - if (controlSystems.containsKey(new Integer(id))) { - return controlSystems.get(new Integer(id)); - } else { - EveningActivityControlSystem scs = - new EveningActivityControlSystem(id); - controlSystems.put(new Integer(id), scs); - return scs; - } - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.HashMap; +import java.util.List; +import java.util.Random; + +import core.Coord; +import core.DTNSim; + +/** + * This class controls the group mobility of the people meeting their friends in + * the evening + * + * @author Frans Ekman + */ +public class EveningActivityControlSystem { + + private HashMap eveningActivityNodes; + private List meetingSpots; + private EveningTrip[] nextTrips; + + private Random rng; + + private static HashMap + controlSystems; + + static { + DTNSim.registerForReset(EveningActivityControlSystem.class. + getCanonicalName()); + reset(); + } + + /** + * Creates a new instance of EveningActivityControlSystem without any nodes + * or meeting spots, with the ID given as parameter + * @param id + */ + private EveningActivityControlSystem(int id) { + eveningActivityNodes = new HashMap(); + } + + public static void reset() { + controlSystems = new HashMap(); + } + + /** + * Register a evening activity node with the system + * @param eveningMovement activity movement + */ + public void addEveningActivityNode(EveningActivityMovement eveningMovement) { + eveningActivityNodes.put(new Integer(eveningMovement.getID()), + eveningMovement); + } + + /** + * Sets the meeting locations the nodes can choose among + * @param meetingSpots + */ + public void setMeetingSpots(List meetingSpots) { + this.meetingSpots = meetingSpots; + this.nextTrips = new EveningTrip[meetingSpots.size()]; + } + + /** + * This method gets the instruction for a node, i.e. When/where and with + * whom to go. + * @param eveningActivityNodeID unique ID of the node + * @return Instructions object + */ + public EveningTrip getEveningInstructions(int eveningActivityNodeID) { + EveningActivityMovement eveningMovement = eveningActivityNodes.get( + new Integer(eveningActivityNodeID)); + if (eveningMovement != null) { + int index = eveningActivityNodeID % meetingSpots.size(); + if (nextTrips[index] == null) { + int nrOfEveningMovementNodes = (int)(eveningMovement. + getMinGroupSize() + + (double)(eveningMovement.getMaxGroupSize() - + eveningMovement.getMinGroupSize()) * + rng.nextDouble()); + Coord loc = meetingSpots.get(index).clone(); + nextTrips[index] = new EveningTrip(nrOfEveningMovementNodes, + loc); + } + nextTrips[index].addNode(eveningMovement); + if (nextTrips[index].isFull()) { + EveningTrip temp = nextTrips[index]; + nextTrips[index] = null; + return temp; + } else { + return nextTrips[index]; + } + } + return null; + } + + /** + * Get the meeting spot for the node + * @param id + * @return Coordinates of the spot + */ + public Coord getMeetingSpotForID(int id) { + int index = id % meetingSpots.size(); + Coord loc = meetingSpots.get(index).clone(); + return loc; + } + + + /** + * Sets the random number generator to be used + * @param rand + */ + public void setRandomNumberGenerator(Random rand) { + this.rng = rand; + } + + /** + * Returns a reference to a EveningActivityControlSystem with ID provided as + * parameter. If a system does not already exist with the requested ID, a + * new one is created. + * @param id unique ID of the EveningActivityControlSystem + * @return The EveningActivityControlSystem with the provided ID + */ + public static EveningActivityControlSystem getEveningActivityControlSystem( + int id) { + if (controlSystems.containsKey(new Integer(id))) { + return controlSystems.get(new Integer(id)); + } else { + EveningActivityControlSystem scs = + new EveningActivityControlSystem(id); + controlSystems.put(new Integer(id), scs); + return scs; + } + } + +} diff --git a/movement/EveningActivityMovement.java b/movement/EveningActivityMovement.java index 60fbf6074..f5a1458b2 100644 --- a/movement/EveningActivityMovement.java +++ b/movement/EveningActivityMovement.java @@ -1,299 +1,299 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import input.WKTReader; - -import java.io.File; -import java.util.LinkedList; -import java.util.List; - -import movement.map.DijkstraPathFinder; -import movement.map.MapNode; -import movement.map.SimMap; -import core.Coord; -import core.Settings; - -/** - * A Class to model movement when people are out shopping or doing other - * activities with friends. If the node happens to be at some other location - * than the place where the shopping starts (where it meets its friends), it - * first travels to the destination along the shortest path. - * - * @author Frans Ekman - */ -public class EveningActivityMovement extends MapBasedMovement - implements SwitchableMovement { - - private static final int WALKING_TO_MEETING_SPOT_MODE = 0; - private static final int EVENING_ACTIVITY_MODE = 1; - - public static final String NR_OF_MEETING_SPOTS_SETTING = "nrOfMeetingSpots"; - public static final String EVENING_ACTIVITY_CONTROL_SYSTEM_NR_SETTING = - "shoppingControlSystemNr"; - - public static final String MEETING_SPOTS_FILE_SETTING = "meetingSpotsFile"; - - public static final String MIN_GROUP_SIZE_SETTING = "minGroupSize"; - public static final String MAX_GROUP_SIZE_SETTING = "maxGroupSize"; - - public static final String MIN_WAIT_TIME_SETTING = - "minAfterShoppingStopTime"; - public static final String MAX_WAIT_TIME_SETTING = - "maxAfterShoppingStopTime"; - - private static int nrOfMeetingSpots = 10; - - private int mode; - private boolean ready; - private DijkstraPathFinder pathFinder; - - private Coord lastWaypoint; - private Coord startAtLocation; - - private EveningActivityControlSystem scs; - private EveningTrip trip; - - private boolean readyToShop; - - private int id; - - private static int nextID = 0; - - private int minGroupSize; - private int maxGroupSize; - - /** - * Creates a new instance of EveningActivityMovement - * @param settings - */ - public EveningActivityMovement(Settings settings) { - super(settings); - super.backAllowed = false; - pathFinder = new DijkstraPathFinder(null); - mode = WALKING_TO_MEETING_SPOT_MODE; - - nrOfMeetingSpots = settings.getInt(NR_OF_MEETING_SPOTS_SETTING); - - minGroupSize = settings.getInt(MIN_GROUP_SIZE_SETTING); - maxGroupSize = settings.getInt(MAX_GROUP_SIZE_SETTING); - - MapNode[] mapNodes = (MapNode[])getMap().getNodes(). - toArray(new MapNode[0]); - - String shoppingSpotsFile = null; - try { - shoppingSpotsFile = settings.getSetting(MEETING_SPOTS_FILE_SETTING); - } catch (Throwable t) { - // Do nothing; - } - - List meetingSpotLocations = null; - - if (shoppingSpotsFile == null) { - meetingSpotLocations = new LinkedList(); - for (int i=0; i(); - List locationsRead = (new WKTReader()).readPoints( - new File(shoppingSpotsFile)); - for (Coord coord : locationsRead) { - SimMap map = getMap(); - Coord offset = map.getOffset(); - // mirror points if map data is mirrored - if (map.isMirrored()) { - coord.setLocation(coord.getX(), -coord.getY()); - } - coord.translate(offset.getX(), offset.getY()); - meetingSpotLocations.add(coord); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - this.id = nextID++; - - int scsID = settings.getInt(EVENING_ACTIVITY_CONTROL_SYSTEM_NR_SETTING); - - scs = EveningActivityControlSystem.getEveningActivityControlSystem(scsID); - scs.setRandomNumberGenerator(rng); - scs.addEveningActivityNode(this); - scs.setMeetingSpots(meetingSpotLocations); - - maxPathLength = 100; - minPathLength = 10; - - maxWaitTime = settings.getInt(MAX_WAIT_TIME_SETTING); - minWaitTime = settings.getInt(MIN_WAIT_TIME_SETTING); - } - - /** - * Creates a new instance of EveningActivityMovement from a prototype - * @param proto - */ - public EveningActivityMovement(EveningActivityMovement proto) { - super(proto); - this.pathFinder = proto.pathFinder; - this.mode = proto.mode; - this.id = nextID++; - scs = proto.scs; - scs.addEveningActivityNode(this); - this.setMinGroupSize(proto.getMinGroupSize()); - this.setMaxGroupSize(proto.getMaxGroupSize()); - } - - /** - * @return Unique ID of the shopper - */ - public int getID() { - return this.id; - } - - @Override - public Coord getInitialLocation() { - - MapNode[] mapNodes = (MapNode[])getMap().getNodes(). - toArray(new MapNode[0]); - int index = rng.nextInt(mapNodes.length - 1); - lastWaypoint = mapNodes[index].getLocation().clone(); - return lastWaypoint.clone(); - } - - @Override - public Path getPath() { - if (mode == WALKING_TO_MEETING_SPOT_MODE) { - // Try to find to the shopping center - SimMap map = super.getMap(); - if (map == null) { - return null; - } - MapNode thisNode = map.getNodeByCoord(lastWaypoint); - MapNode destinationNode = map.getNodeByCoord(startAtLocation); - - List nodes = pathFinder.getShortestPath(thisNode, - destinationNode); - Path path = new Path(generateSpeed()); - for (MapNode node : nodes) { - path.addWaypoint(node.getLocation()); - } - lastWaypoint = startAtLocation.clone(); - mode = EVENING_ACTIVITY_MODE; - return path; - } else if (mode == EVENING_ACTIVITY_MODE) { - readyToShop = true; - if (trip.allMembersPresent()) { - Path path = trip.getPath(); - if (path == null) { - super.lastMapNode = super.getMap(). - getNodeByCoord(lastWaypoint); - path = super.getPath(); // TODO Create levy walk path - lastWaypoint = super.lastMapNode.getLocation(); - trip.setPath(path); - double waitTimeAtEnd = (maxWaitTime - minWaitTime) * - rng.nextDouble() + minWaitTime; - trip.setWaitTimeAtEnd(waitTimeAtEnd); - trip.setDestination(lastWaypoint); - } - lastWaypoint = trip.getDestination(); - ready = true; - return path; - } - } - - return null; - } - - @Override - protected double generateWaitTime() { - if (ready) { - double wait = trip.getWaitTimeAtEnd(); - return wait; - } else { - return 0; - } - } - - @Override - public MapBasedMovement replicate() { - return new EveningActivityMovement(this); - } - - /** - * @see SwitchableMovement - */ - public Coord getLastLocation() { - return lastWaypoint.clone(); - } - - /** - * @see SwitchableMovement - */ - public boolean isReady() { - return ready; - } - - /** - * @see SwitchableMovement - */ - public void setLocation(Coord lastWaypoint) { - this.lastWaypoint = lastWaypoint.clone(); - ready = false; - mode = WALKING_TO_MEETING_SPOT_MODE; - } - - /** - * Sets the node ready to start a shopping trip. - * @return The coordinate of the place where the shopping trip starts - */ - public Coord getShoppingLocationAndGetReady() { - readyToShop = false; // New shopping round starts - trip = scs.getEveningInstructions(id); - startAtLocation = trip.getLocation().clone(); - return startAtLocation.clone(); - } - - - public Coord getShoppingLocation() { - return scs.getMeetingSpotForID(id).clone(); - } - - - /** - * Checks if a node is at the correct place where the shopping begins - * @return true if node is ready and waiting for the rest of the group to - * arrive - */ - public boolean isReadyToShop() { - return readyToShop; - } - - public static void reset() { - nextID = 0; - } - - public int getMinGroupSize() { - return minGroupSize; - } - - public void setMinGroupSize(int minGroupSize) { - this.minGroupSize = minGroupSize; - } - - public int getMaxGroupSize() { - return maxGroupSize; - } - - public void setMaxGroupSize(int maxGroupSize) { - this.maxGroupSize = maxGroupSize; - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import input.WKTReader; + +import java.io.File; +import java.util.LinkedList; +import java.util.List; + +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import movement.map.SimMap; +import core.Coord; +import core.Settings; + +/** + * A Class to model movement when people are out shopping or doing other + * activities with friends. If the node happens to be at some other location + * than the place where the shopping starts (where it meets its friends), it + * first travels to the destination along the shortest path. + * + * @author Frans Ekman + */ +public class EveningActivityMovement extends MapBasedMovement + implements SwitchableMovement { + + private static final int WALKING_TO_MEETING_SPOT_MODE = 0; + private static final int EVENING_ACTIVITY_MODE = 1; + + public static final String NR_OF_MEETING_SPOTS_SETTING = "nrOfMeetingSpots"; + public static final String EVENING_ACTIVITY_CONTROL_SYSTEM_NR_SETTING = + "shoppingControlSystemNr"; + + public static final String MEETING_SPOTS_FILE_SETTING = "meetingSpotsFile"; + + public static final String MIN_GROUP_SIZE_SETTING = "minGroupSize"; + public static final String MAX_GROUP_SIZE_SETTING = "maxGroupSize"; + + public static final String MIN_WAIT_TIME_SETTING = + "minAfterShoppingStopTime"; + public static final String MAX_WAIT_TIME_SETTING = + "maxAfterShoppingStopTime"; + + private static int nrOfMeetingSpots = 10; + + private int mode; + private boolean ready; + private DijkstraPathFinder pathFinder; + + private Coord lastWaypoint; + private Coord startAtLocation; + + private EveningActivityControlSystem scs; + private EveningTrip trip; + + private boolean readyToShop; + + private int id; + + private static int nextID = 0; + + private int minGroupSize; + private int maxGroupSize; + + /** + * Creates a new instance of EveningActivityMovement + * @param settings + */ + public EveningActivityMovement(Settings settings) { + super(settings); + super.backAllowed = false; + pathFinder = new DijkstraPathFinder(null); + mode = WALKING_TO_MEETING_SPOT_MODE; + + nrOfMeetingSpots = settings.getInt(NR_OF_MEETING_SPOTS_SETTING); + + minGroupSize = settings.getInt(MIN_GROUP_SIZE_SETTING); + maxGroupSize = settings.getInt(MAX_GROUP_SIZE_SETTING); + + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + + String shoppingSpotsFile = null; + try { + shoppingSpotsFile = settings.getSetting(MEETING_SPOTS_FILE_SETTING); + } catch (Throwable t) { + // Do nothing; + } + + List meetingSpotLocations = null; + + if (shoppingSpotsFile == null) { + meetingSpotLocations = new LinkedList(); + for (int i=0; i(); + List locationsRead = (new WKTReader()).readPoints( + new File(shoppingSpotsFile)); + for (Coord coord : locationsRead) { + SimMap map = getMap(); + Coord offset = map.getOffset(); + // mirror points if map data is mirrored + if (map.isMirrored()) { + coord.setLocation(coord.getX(), -coord.getY()); + } + coord.translate(offset.getX(), offset.getY()); + meetingSpotLocations.add(coord); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + this.id = nextID++; + + int scsID = settings.getInt(EVENING_ACTIVITY_CONTROL_SYSTEM_NR_SETTING); + + scs = EveningActivityControlSystem.getEveningActivityControlSystem(scsID); + scs.setRandomNumberGenerator(rng); + scs.addEveningActivityNode(this); + scs.setMeetingSpots(meetingSpotLocations); + + maxPathLength = 100; + minPathLength = 10; + + maxWaitTime = settings.getInt(MAX_WAIT_TIME_SETTING); + minWaitTime = settings.getInt(MIN_WAIT_TIME_SETTING); + } + + /** + * Creates a new instance of EveningActivityMovement from a prototype + * @param proto + */ + public EveningActivityMovement(EveningActivityMovement proto) { + super(proto); + this.pathFinder = proto.pathFinder; + this.mode = proto.mode; + this.id = nextID++; + scs = proto.scs; + scs.addEveningActivityNode(this); + this.setMinGroupSize(proto.getMinGroupSize()); + this.setMaxGroupSize(proto.getMaxGroupSize()); + } + + /** + * @return Unique ID of the shopper + */ + public int getID() { + return this.id; + } + + @Override + public Coord getInitialLocation() { + + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int index = rng.nextInt(mapNodes.length - 1); + lastWaypoint = mapNodes[index].getLocation().clone(); + return lastWaypoint.clone(); + } + + @Override + public Path getPath() { + if (mode == WALKING_TO_MEETING_SPOT_MODE) { + // Try to find to the shopping center + SimMap map = super.getMap(); + if (map == null) { + return null; + } + MapNode thisNode = map.getNodeByCoord(lastWaypoint); + MapNode destinationNode = map.getNodeByCoord(startAtLocation); + + List nodes = pathFinder.getShortestPath(thisNode, + destinationNode); + Path path = new Path(generateSpeed()); + for (MapNode node : nodes) { + path.addWaypoint(node.getLocation()); + } + lastWaypoint = startAtLocation.clone(); + mode = EVENING_ACTIVITY_MODE; + return path; + } else if (mode == EVENING_ACTIVITY_MODE) { + readyToShop = true; + if (trip.allMembersPresent()) { + Path path = trip.getPath(); + if (path == null) { + super.lastMapNode = super.getMap(). + getNodeByCoord(lastWaypoint); + path = super.getPath(); // TODO Create levy walk path + lastWaypoint = super.lastMapNode.getLocation(); + trip.setPath(path); + double waitTimeAtEnd = (maxWaitTime - minWaitTime) * + rng.nextDouble() + minWaitTime; + trip.setWaitTimeAtEnd(waitTimeAtEnd); + trip.setDestination(lastWaypoint); + } + lastWaypoint = trip.getDestination(); + ready = true; + return path; + } + } + + return null; + } + + @Override + protected double generateWaitTime() { + if (ready) { + double wait = trip.getWaitTimeAtEnd(); + return wait; + } else { + return 0; + } + } + + @Override + public MapBasedMovement replicate() { + return new EveningActivityMovement(this); + } + + /** + * @see SwitchableMovement + */ + public Coord getLastLocation() { + return lastWaypoint.clone(); + } + + /** + * @see SwitchableMovement + */ + public boolean isReady() { + return ready; + } + + /** + * @see SwitchableMovement + */ + public void setLocation(Coord lastWaypoint) { + this.lastWaypoint = lastWaypoint.clone(); + ready = false; + mode = WALKING_TO_MEETING_SPOT_MODE; + } + + /** + * Sets the node ready to start a shopping trip. + * @return The coordinate of the place where the shopping trip starts + */ + public Coord getShoppingLocationAndGetReady() { + readyToShop = false; // New shopping round starts + trip = scs.getEveningInstructions(id); + startAtLocation = trip.getLocation().clone(); + return startAtLocation.clone(); + } + + + public Coord getShoppingLocation() { + return scs.getMeetingSpotForID(id).clone(); + } + + + /** + * Checks if a node is at the correct place where the shopping begins + * @return true if node is ready and waiting for the rest of the group to + * arrive + */ + public boolean isReadyToShop() { + return readyToShop; + } + + public static void reset() { + nextID = 0; + } + + public int getMinGroupSize() { + return minGroupSize; + } + + public void setMinGroupSize(int minGroupSize) { + this.minGroupSize = minGroupSize; + } + + public int getMaxGroupSize() { + return maxGroupSize; + } + + public void setMaxGroupSize(int maxGroupSize) { + this.maxGroupSize = maxGroupSize; + } + +} diff --git a/movement/EveningTrip.java b/movement/EveningTrip.java index 8e34e3825..0d8344b00 100644 --- a/movement/EveningTrip.java +++ b/movement/EveningTrip.java @@ -1,128 +1,128 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import core.Coord; - -/** - * A class to encapsulate information about a shopping trip - * 1. Where the trip begins - * 2. Where it ends - * 3. The path - * 4. All nodes in the group - * - * @author Frans Ekman - */ -public class EveningTrip { - private EveningActivityMovement[] eveningActivityNodes; - private int eveningActivityNodesInBuffer; - private Path path; - private Coord location; - private Coord destination; - private double waitTimeAtEnd; - - /** - * Create a new instance of a EveningTrip - * @param nrOfeveningActivityNodes The number of shoppers in the group - * @param location Where the trip starts - */ - public EveningTrip(int nrOfeveningActivityNodes, Coord location) { - eveningActivityNodes = - new EveningActivityMovement[nrOfeveningActivityNodes]; - this.location = location; - eveningActivityNodesInBuffer = 0; - } - - /** - * Add an evening activity node to the group - * @param eveningActivityNode - * @return true if there was room in the group - */ - public boolean addNode(EveningActivityMovement eveningActivityNode) { - if (isFull()) { - return false; - } else { - eveningActivityNodes[eveningActivityNodesInBuffer] = - eveningActivityNode; - eveningActivityNodesInBuffer++; - return true; - } - } - - /** - * Sets the shopping path for the group - * @param path - */ - public void setPath(Path path) { - this.path = new Path(path); - } - - /** - * @return The shopping trip path - */ - public Path getPath() { - if (path != null) { - return new Path(this.path); - } else { - return null; - } - } - - /** - * @return The location where the shopping trip starts - */ - public Coord getLocation() { - return location; - } - - /** - * @return true if the group is full - */ - public boolean isFull() { - return eveningActivityNodesInBuffer >= eveningActivityNodes.length; - } - - /** - * Checks if all members of the group have found their way to the meeting - * point - * @return true if all nodes are there - */ - public boolean allMembersPresent() { - if (!isFull()) { - return false; - } - for (int i=0; i= eveningActivityNodes.length; + } + + /** + * Checks if all members of the group have found their way to the meeting + * point + * @return true if all nodes are there + */ + public boolean allMembersPresent() { + if (!isFull()) { + return false; + } + for (int i=0; i idMapping; - /** initial locations for nodes */ - private static List> initLocations; - /** time of the very first location data */ - private static double initTime; - /** sampling interval (seconds) of the location data */ - private static double samplingInterval; - /** last read time stamp after preloading */ - private static double lastPreloadTime; - /** how many time intervals to load on every preload run */ - private static double nrofPreload = 10; - /** minimum number intervals that should be preloaded ahead of sim time */ - private static final double MIN_AHEAD_INTERVALS = 2; - - /** the very first location of the node */ - private Coord intialLocation; - /** queue of path-start-time, path tuples */ - private Queue> pathQueue; - - /** when was the path currently under construction started */ - private double latestPathStartTime; - /** the last location of path waypoint */ - private Coord latestLocation; - /** the path currently under construction */ - private Path latestPath; - - /** is this node active */ - private boolean isActive; - + +/** + * Movement model that uses external data of node locations. + */ +public class ExternalMovement extends MovementModel { + /** Namespace for settings */ + public static final String EXTERNAL_MOVEMENT_NS = "ExternalMovement"; + /** external locations file's path -setting id ({@value})*/ + public static final String MOVEMENT_FILE_S = "file"; + /** number of preloaded intervals per preload run -setting id ({@value})*/ + public static final String NROF_PRELOAD_S = "nrofPreload"; + + /** default initial location for excess nodes */ + private static final Coord DEF_INIT_LOC = new Coord(0,0); + private static ExternalMovementReader reader; + private static String inputFileName; + + /** mapping of external id to movement model */ + private static Map idMapping; + /** initial locations for nodes */ + private static List> initLocations; + /** time of the very first location data */ + private static double initTime; + /** sampling interval (seconds) of the location data */ + private static double samplingInterval; + /** last read time stamp after preloading */ + private static double lastPreloadTime; + /** how many time intervals to load on every preload run */ + private static double nrofPreload = 10; + /** minimum number intervals that should be preloaded ahead of sim time */ + private static final double MIN_AHEAD_INTERVALS = 2; + + /** the very first location of the node */ + private Coord intialLocation; + /** queue of path-start-time, path tuples */ + private Queue> pathQueue; + + /** when was the path currently under construction started */ + private double latestPathStartTime; + /** the last location of path waypoint */ + private Coord latestLocation; + /** the path currently under construction */ + private Path latestPath; + + /** is this node active */ + private boolean isActive; + static { - DTNSim.registerForReset(ExternalMovement.class.getCanonicalName()); - reset(); - } - - /** - * Constructor for the prototype. Run once per group. - * @param settings Where settings are read from - */ - public ExternalMovement(Settings settings) { - super(settings); - - if (idMapping == null) { - // run these the first time object is created or after reset call - Settings s = new Settings(EXTERNAL_MOVEMENT_NS); - idMapping = new HashMap(); - inputFileName = s.getSetting(MOVEMENT_FILE_S); - reader = new ExternalMovementReader(inputFileName); - - initLocations = reader.readNextMovements(); - initTime = reader.getLastTimeStamp(); - samplingInterval = -1; - lastPreloadTime = -1; - - s.setNameSpace(EXTERNAL_MOVEMENT_NS); - if (s.contains(NROF_PRELOAD_S)) { - nrofPreload = s.getInt(NROF_PRELOAD_S); - if (nrofPreload <= 0) { - nrofPreload = 1; - } - } - } - } - - /** - * Copy constructor. Gives out location data for the new node from - * location queue. - * @param mm The movement model to copy from - */ - private ExternalMovement(MovementModel mm) { - super(mm); - - pathQueue = new LinkedList>(); - latestPath = null; - - if (initLocations.size() > 0) { // we have location data left - // gets a new location from the list - Tuple initLoc = initLocations.remove(0); - this.intialLocation = this.latestLocation = initLoc.getValue(); - this.latestPathStartTime = initTime; - - // puts the new model to model map for later updates - idMapping.put(initLoc.getKey(), this); - isActive = true; - } - else { - // no more location data left for the new node -> set inactive - this.intialLocation = DEF_INIT_LOC; - isActive = false; - } - } - - /** - * Checks if more paths should be preloaded and preloads them if - * needed. - */ - private static void checkPathNeed() { - if (samplingInterval == -1) { // first preload - lastPreloadTime = readMorePaths(); - } - - if (!Double.isNaN(lastPreloadTime) && SimClock.getTime() >= - lastPreloadTime - (samplingInterval * MIN_AHEAD_INTERVALS) ) { - for (int i=0; i < nrofPreload && - !Double.isNaN(lastPreloadTime); i++) { - lastPreloadTime = readMorePaths(); - } - } - } - - @Override - public Coord getInitialLocation() { - return this.intialLocation; - } - - @Override - public boolean isActive() { - return isActive; - } - - /** - * Adds a new location with a time to this model's move pattern. If the - * node stayed stationary during the update, the current path is put to the - * queue and a new path is started once the node starts moving. - * @param loc The location - * @param time When should the node be there - */ - private void addLocation(Coord loc, double time) { + DTNSim.registerForReset(ExternalMovement.class.getCanonicalName()); + reset(); + } + + /** + * Constructor for the prototype. Run once per group. + * @param settings Where settings are read from + */ + public ExternalMovement(Settings settings) { + super(settings); + + if (idMapping == null) { + // run these the first time object is created or after reset call + Settings s = new Settings(EXTERNAL_MOVEMENT_NS); + idMapping = new HashMap(); + inputFileName = s.getSetting(MOVEMENT_FILE_S); + reader = new ExternalMovementReader(inputFileName); + + initLocations = reader.readNextMovements(); + initTime = reader.getLastTimeStamp(); + samplingInterval = -1; + lastPreloadTime = -1; + + s.setNameSpace(EXTERNAL_MOVEMENT_NS); + if (s.contains(NROF_PRELOAD_S)) { + nrofPreload = s.getInt(NROF_PRELOAD_S); + if (nrofPreload <= 0) { + nrofPreload = 1; + } + } + } + } + + /** + * Copy constructor. Gives out location data for the new node from + * location queue. + * @param mm The movement model to copy from + */ + private ExternalMovement(MovementModel mm) { + super(mm); + + pathQueue = new LinkedList>(); + latestPath = null; + + if (initLocations.size() > 0) { // we have location data left + // gets a new location from the list + Tuple initLoc = initLocations.remove(0); + this.intialLocation = this.latestLocation = initLoc.getValue(); + this.latestPathStartTime = initTime; + + // puts the new model to model map for later updates + idMapping.put(initLoc.getKey(), this); + isActive = true; + } + else { + // no more location data left for the new node -> set inactive + this.intialLocation = DEF_INIT_LOC; + isActive = false; + } + } + + /** + * Checks if more paths should be preloaded and preloads them if + * needed. + */ + private static void checkPathNeed() { + if (samplingInterval == -1) { // first preload + lastPreloadTime = readMorePaths(); + } + + if (!Double.isNaN(lastPreloadTime) && SimClock.getTime() >= + lastPreloadTime - (samplingInterval * MIN_AHEAD_INTERVALS) ) { + for (int i=0; i < nrofPreload && + !Double.isNaN(lastPreloadTime); i++) { + lastPreloadTime = readMorePaths(); + } + } + } + + @Override + public Coord getInitialLocation() { + return this.intialLocation; + } + + @Override + public boolean isActive() { + return isActive; + } + + /** + * Adds a new location with a time to this model's move pattern. If the + * node stayed stationary during the update, the current path is put to the + * queue and a new path is started once the node starts moving. + * @param loc The location + * @param time When should the node be there + */ + private void addLocation(Coord loc, double time) { assert samplingInterval > 0 : "Non-positive sampling interval!"; - - if (loc.equals(latestLocation)) { // node didn't move - if (latestPath != null) { - // constructing path -> end constructing and put it in the queue - pathQueue.add(new Tuple - (latestPathStartTime, latestPath)); - latestPath = null; - } - - this.latestPathStartTime = time; - return; - } - - if (latestPath == null) { - latestPath = new Path(); - } - - double speed = loc.distance(this.latestLocation) / samplingInterval; - latestPath.addWaypoint(loc, speed); - - this.latestLocation = loc; - } - - /** - * Returns a sim time when the next path is available. - * @return The sim time when node should ask the next time for a path - */ - @Override - public double nextPathAvailable() { - if (pathQueue.size() == 0) { - return latestPathStartTime; - } - else { - return pathQueue.element().getKey(); - } - } - - @Override - public Path getPath() { - Path p; - - checkPathNeed(); // check if we should preload more paths - + + if (loc.equals(latestLocation)) { // node didn't move + if (latestPath != null) { + // constructing path -> end constructing and put it in the queue + pathQueue.add(new Tuple + (latestPathStartTime, latestPath)); + latestPath = null; + } + + this.latestPathStartTime = time; + return; + } + + if (latestPath == null) { + latestPath = new Path(); + } + + double speed = loc.distance(this.latestLocation) / samplingInterval; + latestPath.addWaypoint(loc, speed); + + this.latestLocation = loc; + } + + /** + * Returns a sim time when the next path is available. + * @return The sim time when node should ask the next time for a path + */ + @Override + public double nextPathAvailable() { + if (pathQueue.size() == 0) { + return latestPathStartTime; + } + else { + return pathQueue.element().getKey(); + } + } + + @Override + public Path getPath() { + Path p; + + checkPathNeed(); // check if we should preload more paths + if (SimClock.getTime() < this.nextPathAvailable()) { return null; - } - - if (pathQueue.size() == 0) { // nothing in the queue, return latest - p = latestPath; - latestPath = null; - } - else { // return first path in the queue - p = pathQueue.remove().getValue(); - } - - return p; - } - - @Override - public int getMaxX() { - return (int)(reader.getMaxX() - reader.getMinX()) + 1; - } - - @Override - public int getMaxY() { - return (int)(reader.getMaxY() - reader.getMinY()) + 1; - } - - - @Override - public MovementModel replicate() { - return new ExternalMovement(this); - } - - /** - * Reads paths for the next time instance from the reader - * @return The time stamp of the reading or Double.NaN if no movements - * were read. - */ - private static double readMorePaths() { - List> list = reader.readNextMovements(); - double time = reader.getLastTimeStamp(); - - if (samplingInterval == -1) { - samplingInterval = time - initTime; - } - - for (Tuple t : list) { - ExternalMovement em = idMapping.get(t.getKey()); - if (em != null) { // skip unknown IDs, i.e. IDs not mentioned in... - // ...init phase or if there are more IDs than nodes - em.addLocation(t.getValue(), time); - } - } - - if (list.size() > 0) { - return time; - } - else { - return Double.NaN; - } - } - - /** - * Reset state so that next instance will have a fresh state - */ - public static void reset() { - idMapping = null; - } - -} + } + + if (pathQueue.size() == 0) { // nothing in the queue, return latest + p = latestPath; + latestPath = null; + } + else { // return first path in the queue + p = pathQueue.remove().getValue(); + } + + return p; + } + + @Override + public int getMaxX() { + return (int)(reader.getMaxX() - reader.getMinX()) + 1; + } + + @Override + public int getMaxY() { + return (int)(reader.getMaxY() - reader.getMinY()) + 1; + } + + + @Override + public MovementModel replicate() { + return new ExternalMovement(this); + } + + /** + * Reads paths for the next time instance from the reader + * @return The time stamp of the reading or Double.NaN if no movements + * were read. + */ + private static double readMorePaths() { + List> list = reader.readNextMovements(); + double time = reader.getLastTimeStamp(); + + if (samplingInterval == -1) { + samplingInterval = time - initTime; + } + + for (Tuple t : list) { + ExternalMovement em = idMapping.get(t.getKey()); + if (em != null) { // skip unknown IDs, i.e. IDs not mentioned in... + // ...init phase or if there are more IDs than nodes + em.addLocation(t.getValue(), time); + } + } + + if (list.size() > 0) { + return time; + } + else { + return Double.NaN; + } + } + + /** + * Reset state so that next instance will have a fresh state + */ + public static void reset() { + idMapping = null; + } + +} diff --git a/movement/ExternalPathMovement.java b/movement/ExternalPathMovement.java index bdc9e34f4..f9727d28a 100644 --- a/movement/ExternalPathMovement.java +++ b/movement/ExternalPathMovement.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package movement; @@ -13,10 +13,10 @@ import core.Settings; import core.SimClock; -/** +/** * External movement trace reader for traces that are in path format. * See ExternalPathMovementReader for details. - * + * * @author teemuk * */ @@ -25,32 +25,32 @@ public class ExternalPathMovement extends MovementModel { public static final String MOVEMENT_FILE_S = "traceFile"; /** activity file's path -setting id ({@value})*/ public static final String ACTIVITY_FILE_S = "activeFile"; - + // Settings private String traceFile; private String activeFile; - + // Node's paths private List> paths; private int curPath=0; private List active; - + public ExternalPathMovement(Settings settings) { this.traceFile = settings.getSetting(MOVEMENT_FILE_S); this.activeFile = settings.getSetting(ACTIVITY_FILE_S); } - - /** + + /** * Copy-constructor. - * + * * @param mm */ public ExternalPathMovement(ExternalPathMovement mm) { this.traceFile = mm.traceFile; this.activeFile = mm.activeFile; } - - /** + + /** * Initializes the movement model. Uses a reader to get the paths for this * host. */ @@ -62,22 +62,22 @@ private void init() { this.paths = reader.getPaths(getHost().getAddress()); this.active = reader.getActive(getHost().getAddress()); } - + @Override public void setHost(DTNHost host) { super.setHost(host); this.init(); // Can only initialize after the host has been set } - + @Override public boolean isActive() { double t = SimClock.getTime(); - + // Check whether the current time falls in one of the active periods for (ExternalPathMovementReader.ActiveTime a : this.active) { if (t >= a.start && t <= a.end) return true; } - + return false; } @@ -87,18 +87,18 @@ public Path getPath() { if (!this.isActive()) { return null; } - + // Check whether we're moving or waiting for the next path to start double t = SimClock.getTime(); if (t < this.paths.get(this.curPath).get(0).time) { return null; } - + // Get the path List path = this.paths.get(this.curPath); this.curPath++; - + // Drop the node to the the beginning of the new path in case the // previous path ended somewhere else. Coord curPos = super.getHost().getLocation(); @@ -108,7 +108,7 @@ public Path getPath() { Coord c = new Coord(pathStart.x, pathStart.y); super.getHost().setLocation(c); } - + // If this is a stationary path, return only the fist point if (path.size() == 1) { Path p = new Path(0); @@ -117,7 +117,7 @@ public Path getPath() { p.addWaypoint(c); return p; } - + // Build and return the whole path at once Path p = new Path(); for (int i=1; i < path.size(); i++) { @@ -130,7 +130,7 @@ public Path getPath() { double v = ds/dt; p.addWaypoint(c, v); } - + return p; } @@ -151,7 +151,7 @@ public MovementModel replicate() { ExternalPathMovement mm = new ExternalPathMovement(this); return mm; } - + @Override public double nextPathAvailable() { if (this.curPath < this.paths.size()) diff --git a/movement/GridLocation.java b/movement/GridLocation.java index 629bb3ab7..0395706ad 100644 --- a/movement/GridLocation.java +++ b/movement/GridLocation.java @@ -1,31 +1,31 @@ -/* +/* * Copyright 2011 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement; - +package movement; + import core.Coord; import core.Settings; import core.SimScenario; - -/** - * Location (movement) model that sets the nodes in a grid formation - */ + +/** + * Location (movement) model that sets the nodes in a grid formation + */ public class GridLocation extends MovementModel { /** Sub name space for the grid location settings ({@value}) */ - public static final String GRIDLOC_NS = "GridLocation"; + public static final String GRIDLOC_NS = "GridLocation"; /** How many rows of nodes there are -setting ({@value}). * Number of columns is calculated from the node count. */ public static final String ROWS_S = "rows"; /** Space between the nodes -setting ({@value}) */ public static final String SPACING_S = "spacing"; - /** Maximum random offset for the location of the nodes + /** Maximum random offset for the location of the nodes * -setting ({@value}). Default = 0. */ public static final String OFFSET_S = "randomOffset"; - /** Location of the first node (grid's upper left corner) + /** Location of the first node (grid's upper left corner) * -setting ({@value}). Two values: x,y */ public static final String LOCATION_S = "location"; - + private double startCoords[]; private int rows; private int cols; @@ -33,75 +33,75 @@ public class GridLocation extends MovementModel { private double offset; private int nodeCount; private Coord loc; - + /** * Creates a new movement model based on a Settings object's settings. * @param s The Settings object where the settings are read from - */ + */ public GridLocation(Settings s) { super(s); int nodeCount = s.getInt(SimScenario.NROF_HOSTS_S); - + s.setSubNameSpace(GRIDLOC_NS); - + this.rows = s.getInt(ROWS_S); this.cols = (nodeCount / this.rows); this.startCoords = s.getCsvDoubles(LOCATION_S,2); this.spacing = s.getInt(SPACING_S); this.offset = s.getDouble(OFFSET_S, 0); - + s.restoreSubNameSpace(); - } - + } + /** - * Copy constructor. + * Copy constructor. * @param proto The movement model prototype */ public GridLocation(GridLocation proto) { super(proto); double x,y; - - x = proto.startCoords[0] + + + x = proto.startCoords[0] + ((proto.nodeCount) % proto.cols) * proto.spacing; x += rng.nextDouble() * proto.offset; - - y = proto.startCoords[1] + + + y = proto.startCoords[1] + ((proto.nodeCount) / proto.cols) * proto.spacing; y += rng.nextDouble() * proto.offset; - + this.loc = new Coord(x,y); - + proto.nodeCount++; } - - /** - * Returns the only location of this movement model - * @return the only location of this movement model - */ - @Override - public Coord getInitialLocation() { - return loc; - } - - /** - * Returns a single coordinate path (using the only possible coordinate) - * @return a single coordinate path - */ - @Override - public Path getPath() { - Path p = new Path(0); - p.addWaypoint(loc); - return p; - } - - @Override - public double nextPathAvailable() { - return Double.MAX_VALUE; // no new paths available - } - - @Override - public GridLocation replicate() { - return new GridLocation(this); - } - -} + + /** + * Returns the only location of this movement model + * @return the only location of this movement model + */ + @Override + public Coord getInitialLocation() { + return loc; + } + + /** + * Returns a single coordinate path (using the only possible coordinate) + * @return a single coordinate path + */ + @Override + public Path getPath() { + Path p = new Path(0); + p.addWaypoint(loc); + return p; + } + + @Override + public double nextPathAvailable() { + return Double.MAX_VALUE; // no new paths available + } + + @Override + public GridLocation replicate() { + return new GridLocation(this); + } + +} diff --git a/movement/HomeActivityMovement.java b/movement/HomeActivityMovement.java index ba666af6d..1bd0c26d0 100644 --- a/movement/HomeActivityMovement.java +++ b/movement/HomeActivityMovement.java @@ -1,249 +1,249 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import input.WKTReader; - -import java.io.File; -import java.util.LinkedList; -import java.util.List; - -import movement.map.DijkstraPathFinder; -import movement.map.MapNode; -import movement.map.SimMap; -import core.Coord; -import core.Settings; -import core.SimClock; - -/** - * A Class to model movement at home. If the node happens to be at some other - * location than its home, it first walks the shortest path home location and - * then stays there until morning. A node has only one home - * - * @author Frans Ekman - */ -public class HomeActivityMovement extends MapBasedMovement - implements SwitchableMovement { - - private static final int WALKING_HOME_MODE = 0; - private static final int AT_HOME_MODE = 1; - private static final int READY_MODE = 2; - - private static final int DAY_LENGTH = 86000; - - public static final String HOME_LOCATIONS_FILE_SETTING = "homeLocationsFile"; - - public static final String STD_FOR_TIME_DIFF_SETTING = "timeDiffSTD"; - - private int mode; - private DijkstraPathFinder pathFinder; - - private int distance; - - private Coord lastWaypoint; - private Coord homeLocation; - - private List allHomes; - - private int timeDiffSTD; - private int timeDifference; - - /** - * Creates a new instance of HomeActivityMovement - * @param settings - */ - public HomeActivityMovement(Settings settings) { - super(settings); - distance = 100; - pathFinder = new DijkstraPathFinder(null); - mode = WALKING_HOME_MODE; - - String homeLocationsFile = null; - try { - homeLocationsFile = settings.getSetting(HOME_LOCATIONS_FILE_SETTING); - } catch (Throwable t) { - // Do nothing; - } - - timeDiffSTD = settings.getInt(STD_FOR_TIME_DIFF_SETTING); - - if (homeLocationsFile == null) { - MapNode[] mapNodes = (MapNode[])getMap().getNodes(). - toArray(new MapNode[0]); - int homeIndex = rng.nextInt(mapNodes.length - 1); - homeLocation = mapNodes[homeIndex].getLocation().clone(); - } else { - try { - allHomes = new LinkedList(); - List locationsRead = (new WKTReader()).readPoints( - new File(homeLocationsFile)); - for (Coord coord : locationsRead) { - SimMap map = getMap(); - Coord offset = map.getOffset(); - // mirror points if map data is mirrored - if (map.isMirrored()) { - coord.setLocation(coord.getX(), -coord.getY()); - } - coord.translate(offset.getX(), offset.getY()); - allHomes.add(coord); - } - homeLocation = allHomes.get(rng.nextInt(allHomes.size())).clone(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (timeDiffSTD == -1) { - timeDifference = rng.nextInt(DAY_LENGTH) - DAY_LENGTH/2; - } else if (timeDiffSTD == 0) { - timeDifference = 0; - } else { - timeDifference = (int)Math.min( - Math.max( - (rng.nextGaussian() * timeDiffSTD), - -DAY_LENGTH/2 - ), - DAY_LENGTH/2 - ); - } - } - - /** - * Creates a new instance of HomeActivityMovement from a prototype - * @param proto - */ - public HomeActivityMovement(HomeActivityMovement proto) { - super(proto); - this.distance = proto.distance; - this.pathFinder = proto.pathFinder; - this.mode = proto.mode; - - this.timeDiffSTD = proto.timeDiffSTD; - - if (proto.allHomes == null) { - MapNode[] mapNodes = (MapNode[])getMap().getNodes(). - toArray(new MapNode[0]); - int homeIndex = rng.nextInt(mapNodes.length - 1); - homeLocation = mapNodes[homeIndex].getLocation().clone(); - } else { - this.allHomes = proto.allHomes; - homeLocation = allHomes.get(rng.nextInt(allHomes.size())).clone(); - } - - if (timeDiffSTD == -1) { - timeDifference = rng.nextInt(DAY_LENGTH) - DAY_LENGTH/2; - } else if (timeDiffSTD == 0) { - timeDifference = 0; - } else { - timeDifference = (int)Math.min( - Math.max( - (rng.nextGaussian() * timeDiffSTD), - -DAY_LENGTH/2 - ), - DAY_LENGTH/2 - ); - } - } - - @Override - public Coord getInitialLocation() { - double x = rng.nextDouble() * getMaxX(); - double y = rng.nextDouble() * getMaxY(); - Coord c = new Coord(x,y); - - this.lastWaypoint = c; - return c.clone(); - } - - @Override - public Path getPath() { - if (mode == WALKING_HOME_MODE) { - // Try to find home - SimMap map = super.getMap(); - if (map == null) { - return null; - } - MapNode thisNode = map.getNodeByCoord(lastWaypoint); - MapNode destinationNode = map.getNodeByCoord(homeLocation); - List nodes = pathFinder.getShortestPath(thisNode, - destinationNode); - Path path = new Path(generateSpeed()); - for (MapNode node : nodes) { - path.addWaypoint(node.getLocation()); - } - lastWaypoint = homeLocation.clone(); - mode = AT_HOME_MODE; - - double newX = lastWaypoint.getX() + (rng.nextDouble() - 0.5) * - distance; - if (newX > getMaxX()) { - newX = getMaxX(); - } else if (newX < 0) { - newX = 0; - } - double newY = lastWaypoint.getY() + (rng.nextDouble() - 0.5) * - distance; - if (newY > getMaxY()) { - newY = getMaxY(); - } else if (newY < 0) { - newY = 0; - } - Coord c = new Coord(newX, newY); - path.addWaypoint(c); - return path; - } else { - Path path = new Path(1); - path.addWaypoint(lastWaypoint.clone()); - mode = READY_MODE; - return path; - } - - } - - @Override - protected double generateWaitTime() { - if (mode == AT_HOME_MODE) { - return DAY_LENGTH - ((SimClock.getIntTime() + DAY_LENGTH + - timeDifference) % DAY_LENGTH); - } else { - return 0; - } - } - - @Override - public MapBasedMovement replicate() { - return new HomeActivityMovement(this); - } - - /** - * @see SwitchableMovement - */ - public Coord getLastLocation() { - return lastWaypoint.clone(); - } - - /** - * @see SwitchableMovement - */ - public boolean isReady() { - return mode == READY_MODE; - } - - /** - * @see SwitchableMovement - */ - public void setLocation(Coord lastWaypoint) { - this.lastWaypoint = lastWaypoint.clone(); - mode = WALKING_HOME_MODE; - } - - /** - * @return Home location of the node - */ - public Coord getHomeLocation() { - return homeLocation.clone(); - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import input.WKTReader; + +import java.io.File; +import java.util.LinkedList; +import java.util.List; + +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import movement.map.SimMap; +import core.Coord; +import core.Settings; +import core.SimClock; + +/** + * A Class to model movement at home. If the node happens to be at some other + * location than its home, it first walks the shortest path home location and + * then stays there until morning. A node has only one home + * + * @author Frans Ekman + */ +public class HomeActivityMovement extends MapBasedMovement + implements SwitchableMovement { + + private static final int WALKING_HOME_MODE = 0; + private static final int AT_HOME_MODE = 1; + private static final int READY_MODE = 2; + + private static final int DAY_LENGTH = 86000; + + public static final String HOME_LOCATIONS_FILE_SETTING = "homeLocationsFile"; + + public static final String STD_FOR_TIME_DIFF_SETTING = "timeDiffSTD"; + + private int mode; + private DijkstraPathFinder pathFinder; + + private int distance; + + private Coord lastWaypoint; + private Coord homeLocation; + + private List allHomes; + + private int timeDiffSTD; + private int timeDifference; + + /** + * Creates a new instance of HomeActivityMovement + * @param settings + */ + public HomeActivityMovement(Settings settings) { + super(settings); + distance = 100; + pathFinder = new DijkstraPathFinder(null); + mode = WALKING_HOME_MODE; + + String homeLocationsFile = null; + try { + homeLocationsFile = settings.getSetting(HOME_LOCATIONS_FILE_SETTING); + } catch (Throwable t) { + // Do nothing; + } + + timeDiffSTD = settings.getInt(STD_FOR_TIME_DIFF_SETTING); + + if (homeLocationsFile == null) { + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int homeIndex = rng.nextInt(mapNodes.length - 1); + homeLocation = mapNodes[homeIndex].getLocation().clone(); + } else { + try { + allHomes = new LinkedList(); + List locationsRead = (new WKTReader()).readPoints( + new File(homeLocationsFile)); + for (Coord coord : locationsRead) { + SimMap map = getMap(); + Coord offset = map.getOffset(); + // mirror points if map data is mirrored + if (map.isMirrored()) { + coord.setLocation(coord.getX(), -coord.getY()); + } + coord.translate(offset.getX(), offset.getY()); + allHomes.add(coord); + } + homeLocation = allHomes.get(rng.nextInt(allHomes.size())).clone(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (timeDiffSTD == -1) { + timeDifference = rng.nextInt(DAY_LENGTH) - DAY_LENGTH/2; + } else if (timeDiffSTD == 0) { + timeDifference = 0; + } else { + timeDifference = (int)Math.min( + Math.max( + (rng.nextGaussian() * timeDiffSTD), + -DAY_LENGTH/2 + ), + DAY_LENGTH/2 + ); + } + } + + /** + * Creates a new instance of HomeActivityMovement from a prototype + * @param proto + */ + public HomeActivityMovement(HomeActivityMovement proto) { + super(proto); + this.distance = proto.distance; + this.pathFinder = proto.pathFinder; + this.mode = proto.mode; + + this.timeDiffSTD = proto.timeDiffSTD; + + if (proto.allHomes == null) { + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int homeIndex = rng.nextInt(mapNodes.length - 1); + homeLocation = mapNodes[homeIndex].getLocation().clone(); + } else { + this.allHomes = proto.allHomes; + homeLocation = allHomes.get(rng.nextInt(allHomes.size())).clone(); + } + + if (timeDiffSTD == -1) { + timeDifference = rng.nextInt(DAY_LENGTH) - DAY_LENGTH/2; + } else if (timeDiffSTD == 0) { + timeDifference = 0; + } else { + timeDifference = (int)Math.min( + Math.max( + (rng.nextGaussian() * timeDiffSTD), + -DAY_LENGTH/2 + ), + DAY_LENGTH/2 + ); + } + } + + @Override + public Coord getInitialLocation() { + double x = rng.nextDouble() * getMaxX(); + double y = rng.nextDouble() * getMaxY(); + Coord c = new Coord(x,y); + + this.lastWaypoint = c; + return c.clone(); + } + + @Override + public Path getPath() { + if (mode == WALKING_HOME_MODE) { + // Try to find home + SimMap map = super.getMap(); + if (map == null) { + return null; + } + MapNode thisNode = map.getNodeByCoord(lastWaypoint); + MapNode destinationNode = map.getNodeByCoord(homeLocation); + List nodes = pathFinder.getShortestPath(thisNode, + destinationNode); + Path path = new Path(generateSpeed()); + for (MapNode node : nodes) { + path.addWaypoint(node.getLocation()); + } + lastWaypoint = homeLocation.clone(); + mode = AT_HOME_MODE; + + double newX = lastWaypoint.getX() + (rng.nextDouble() - 0.5) * + distance; + if (newX > getMaxX()) { + newX = getMaxX(); + } else if (newX < 0) { + newX = 0; + } + double newY = lastWaypoint.getY() + (rng.nextDouble() - 0.5) * + distance; + if (newY > getMaxY()) { + newY = getMaxY(); + } else if (newY < 0) { + newY = 0; + } + Coord c = new Coord(newX, newY); + path.addWaypoint(c); + return path; + } else { + Path path = new Path(1); + path.addWaypoint(lastWaypoint.clone()); + mode = READY_MODE; + return path; + } + + } + + @Override + protected double generateWaitTime() { + if (mode == AT_HOME_MODE) { + return DAY_LENGTH - ((SimClock.getIntTime() + DAY_LENGTH + + timeDifference) % DAY_LENGTH); + } else { + return 0; + } + } + + @Override + public MapBasedMovement replicate() { + return new HomeActivityMovement(this); + } + + /** + * @see SwitchableMovement + */ + public Coord getLastLocation() { + return lastWaypoint.clone(); + } + + /** + * @see SwitchableMovement + */ + public boolean isReady() { + return mode == READY_MODE; + } + + /** + * @see SwitchableMovement + */ + public void setLocation(Coord lastWaypoint) { + this.lastWaypoint = lastWaypoint.clone(); + mode = WALKING_HOME_MODE; + } + + /** + * @return Home location of the node + */ + public Coord getHomeLocation() { + return homeLocation.clone(); + } + +} diff --git a/movement/LinearFormation.java b/movement/LinearFormation.java index 241e65ced..ab4fcbf5b 100644 --- a/movement/LinearFormation.java +++ b/movement/LinearFormation.java @@ -1,116 +1,116 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement; - +package movement; + import core.Coord; import core.Settings; import movement.MovementModel; -import movement.Path; - -/** +import movement.Path; + +/** * A stationary "movement" model where nodes do not move but are in linear - * formation (i.e., in a line). - */ + * formation (i.e., in a line). + */ public class LinearFormation extends MovementModel { /** Name space of the settings (append to group name space) */ - public static final String LINEAR_FORMATION_NS = "LinearFormation."; - /** Per node group setting for defining the start coordinates of + public static final String LINEAR_FORMATION_NS = "LinearFormation."; + /** Per node group setting for defining the start coordinates of * the line ({@value}) */ public static final String START_LOCATION_S = "startLocation"; - /** Per node group setting for defining the end coordinates of + /** Per node group setting for defining the end coordinates of * the line ({@value}) */ public static final String END_LOCATION_S = "endLocation"; /* values for the prototype */ private Coord startLoc; /** The start location of the line */ - private Coord endLoc; /** The start location of the line */ + private Coord endLoc; /** The start location of the line */ private int nodeCount; /** how many nodes in this formation */ private int lastIndex; /** index of the previous node */ /* values for the per-node models */ private Coord loc; - + /** * Creates a new movement model based on a Settings object's settings. * @param s The Settings object where the settings are read from - */ + */ public LinearFormation(Settings s) { super(s); int coords[]; - + coords = s.getCsvInts(LINEAR_FORMATION_NS + START_LOCATION_S, 2); this.startLoc = new Coord(coords[0], coords[1]); coords = s.getCsvInts(LINEAR_FORMATION_NS + END_LOCATION_S, 2); this.endLoc = new Coord(coords[0], coords[1]); - + this.nodeCount = s.getInt(core.SimScenario.NROF_HOSTS_S); this.lastIndex = 0; - } - + } + /** - * Copy constructor. + * Copy constructor. * @param lf The LinearFormation prototype */ public LinearFormation(LinearFormation lf) { super(lf); this.loc = calculateInitLocation(lf); } - - /** + + /** * Calculates and returns the location of this node in the formation - * @param proto The movement model prototype - * @return the location of the node + * @param proto The movement model prototype + * @return the location of the node */ private Coord calculateInitLocation(LinearFormation proto) { double dx, dy; double placementFraction; int formationIndex = proto.lastIndex++; - + Coord c = proto.startLoc.clone(); - + placementFraction = (1.0 * formationIndex / proto.nodeCount); - dx = placementFraction * + dx = placementFraction * (proto.endLoc.getX() - proto.startLoc.getX()); - dy = placementFraction * + dy = placementFraction * (proto.endLoc.getY() - proto.startLoc.getY()); c.translate(dx, dy); return c; } - + /** * Returns the the location of the node in the formation * @return the the location of the node in the formation - */ - @Override - public Coord getInitialLocation() { + */ + @Override + public Coord getInitialLocation() { return loc; - } - - /** - * Returns a single coordinate path (using the only possible coordinate) - * @return a single coordinate path - */ - @Override - public Path getPath() { - Path p = new Path(0); - p.addWaypoint(loc); - return p; - } - + } + + /** + * Returns a single coordinate path (using the only possible coordinate) + * @return a single coordinate path + */ + @Override + public Path getPath() { + Path p = new Path(0); + p.addWaypoint(loc); + return p; + } + /** * Returns Double.MAX_VALUE (no paths available) - */ - @Override - public double nextPathAvailable() { - return Double.MAX_VALUE; // no new paths available - } - - @Override - public LinearFormation replicate() { - return new LinearFormation(this); - } - -} + */ + @Override + public double nextPathAvailable() { + return Double.MAX_VALUE; // no new paths available + } + + @Override + public LinearFormation replicate() { + return new LinearFormation(this); + } + +} diff --git a/movement/LinearMovement.java b/movement/LinearMovement.java index 4320390ab..b7dfa441a 100644 --- a/movement/LinearMovement.java +++ b/movement/LinearMovement.java @@ -1,43 +1,43 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement; - +package movement; + import core.Coord; import core.Settings; import movement.MovementModel; -import movement.Path; - -/** +import movement.Path; + +/** * Movement model where all nodes move on a line - * (work in progress) - */ + * (work in progress) + */ public class LinearMovement extends MovementModel { /** Name space of the settings (append to group name space) */ - public static final String LINEAR_MOVEMENT_NS = "LinearMovement."; - /** Per node group setting for defining the start coordinates of + public static final String LINEAR_MOVEMENT_NS = "LinearMovement."; + /** Per node group setting for defining the start coordinates of * the line ({@value}) */ public static final String START_LOCATION_S = "startLocation"; - /** Per node group setting for defining the end coordinates of + /** Per node group setting for defining the end coordinates of * the line ({@value}) */ - public static final String END_LOCATION_S = "endLocation"; + public static final String END_LOCATION_S = "endLocation"; - /** + /** * Nodes' initial location type *

  • 0: random (evenly distributed) *
  • 1: evenly spaced *
*/ public static final String INIT_LOC_S = "initLocType"; - /** + /** * Nodes' target (where they're heading) type *
  • 0: random point on the line *
  • 1: far-end of the line *
*/ public static final String TARGET_S = "targetType"; - + /* values for the prototype */ private Coord startLoc; /** The start location of the line */ private Coord endLoc; /** The start location of the line */ @@ -49,28 +49,28 @@ public class LinearMovement extends MovementModel { /* values for the per-node models */ private Path nextPath; private Coord initLoc; - + /** * Creates a new movement model based on a Settings object's settings. * @param s The Settings object where the settings are read from - */ + */ public LinearMovement(Settings s) { super(s); int coords[]; - + coords = s.getCsvInts(LINEAR_MOVEMENT_NS + START_LOCATION_S, 2); this.startLoc = new Coord(coords[0], coords[1]); coords = s.getCsvInts(LINEAR_MOVEMENT_NS + END_LOCATION_S, 2); this.endLoc = new Coord(coords[0], coords[1]); this.initLocType = s.getInt(LINEAR_MOVEMENT_NS + INIT_LOC_S); this.targetType = s.getInt(LINEAR_MOVEMENT_NS + TARGET_S); - this.nodeCount = s.getInt(core.SimScenario.NROF_HOSTS_S); - + this.nodeCount = s.getInt(core.SimScenario.NROF_HOSTS_S); + this.lastIndex = 0; - } - + } + /** - * Copy constructor. + * Copy constructor. * @param lf The LinearFormation prototype */ public LinearMovement(LinearMovement ilm) { @@ -78,29 +78,29 @@ public LinearMovement(LinearMovement ilm) { this.initLoc = calculateLocation(ilm, (ilm.initLocType == 1)); this.nextPath = new Path(generateSpeed()); this.nextPath.addWaypoint(initLoc); - + if (ilm.targetType == 0) { /* random target */ - this.nextPath.addWaypoint(calculateLocation(ilm, true)); + this.nextPath.addWaypoint(calculateLocation(ilm, true)); } else { this.nextPath.addWaypoint(calculateEndTarget(ilm, initLoc)); } - + ilm.lastIndex++; } - - /** + + /** * Calculates and returns a location in the line * @param proto The movement model prototype - * @param isEven Is the distribution evenly spaced (false for random) - * @return a location on the line + * @param isEven Is the distribution evenly spaced (false for random) + * @return a location on the line */ private Coord calculateLocation(LinearMovement proto, boolean isEven) { double dx = 0; double dy = 0; double placementFraction; - + double xDiff = (proto.endLoc.getX() - proto.startLoc.getX()); - double yDiff = (proto.endLoc.getY() - proto.startLoc.getY()); + double yDiff = (proto.endLoc.getY() - proto.startLoc.getY()); Coord c = proto.startLoc.clone(); if (isEven) { @@ -109,72 +109,72 @@ private Coord calculateLocation(LinearMovement proto, boolean isEven) { dy = placementFraction * yDiff; } else { /* random */ dx = rng.nextDouble() * xDiff; - dy = rng.nextDouble() * yDiff; + dy = rng.nextDouble() * yDiff; } - + c.translate(dx, dy); return c; } - + /** * Calculates and returns the far-end of the line * @param proto The movement model prototype * @param initLoc The initial location * @return the coordinates for the far-end of the line */ - private Coord calculateEndTarget(LinearMovement proto, Coord initLoc) { - return (proto.startLoc.distance(initLoc) > + private Coord calculateEndTarget(LinearMovement proto, Coord initLoc) { + return (proto.startLoc.distance(initLoc) > proto.endLoc.distance(initLoc) ? proto.startLoc: proto.endLoc); } - + /** * Returns the the location of the node in the formation * @return the the location of the node in the formation - */ - @Override - public Coord getInitialLocation() { + */ + @Override + public Coord getInitialLocation() { return this.initLoc; - } - - /** - * Returns a single coordinate path (using the only possible coordinate) - * @return a single coordinate path - */ - @Override + } + + /** + * Returns a single coordinate path (using the only possible coordinate) + * @return a single coordinate path + */ + @Override public Path getPath() { Path p = nextPath; - this.nextPath = null; - return p; - } - + this.nextPath = null; + return p; + } + /** * Returns Double.MAX_VALUE (no paths available) - */ - @Override + */ + @Override public double nextPathAvailable() { - if (nextPath == null) { + if (nextPath == null) { return Double.MAX_VALUE; // no new paths available } else { return 0; - } - } - + } + } + @Override - public int getMaxX() { - return (int)(endLoc.getX() > startLoc.getX() ? endLoc.getX() : + public int getMaxX() { + return (int)(endLoc.getX() > startLoc.getX() ? endLoc.getX() : startLoc.getX()); } @Override - public int getMaxY() { - return (int)(endLoc.getY() > startLoc.getY() ? endLoc.getY() : + public int getMaxY() { + return (int)(endLoc.getY() > startLoc.getY() ? endLoc.getY() : startLoc.getY()); } - - @Override - public LinearMovement replicate() { - return new LinearMovement(this); - } - -} + + @Override + public LinearMovement replicate() { + return new LinearMovement(this); + } + +} diff --git a/movement/MapBasedMovement.java b/movement/MapBasedMovement.java index 652047f02..bd3deaf0c 100644 --- a/movement/MapBasedMovement.java +++ b/movement/MapBasedMovement.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement; - +package movement; + import input.WKTMapReader; import java.io.File; @@ -23,384 +23,384 @@ import core.Settings; import core.SettingsError; import core.SimError; - -/** - * Map based movement model which gives out Paths that use the - * roads of a SimMap. - */ -public class MapBasedMovement extends MovementModel implements SwitchableMovement { - /** sim map for the model */ - private SimMap map = null; - /** node where the last path ended or node next to initial placement */ - protected MapNode lastMapNode; - /** max nrof map nodes to travel/path */ - protected int maxPathLength = 100; - /** min nrof map nodes to travel/path */ + +/** + * Map based movement model which gives out Paths that use the + * roads of a SimMap. + */ +public class MapBasedMovement extends MovementModel implements SwitchableMovement { + /** sim map for the model */ + private SimMap map = null; + /** node where the last path ended or node next to initial placement */ + protected MapNode lastMapNode; + /** max nrof map nodes to travel/path */ + protected int maxPathLength = 100; + /** min nrof map nodes to travel/path */ protected int minPathLength = 10; - /** May a node choose to move back the same way it came at a crossing */ - protected boolean backAllowed; - /** map based movement model's settings namespace ({@value})*/ - public static final String MAP_BASE_MOVEMENT_NS = "MapBasedMovement"; - /** number of map files -setting id ({@value})*/ - public static final String NROF_FILES_S = "nrofMapFiles"; - /** map file -setting id ({@value})*/ - public static final String FILE_S = "mapFile"; - - /** - * Per node group setting for selecting map node types that are OK for - * this node group to traverse trough. Value must be a comma separated list - * of integers in range of [1,31]. Values reference to map file indexes - * (see {@link #FILE_S}). If setting is not defined, all map nodes are - * considered OK. - */ - public static final String MAP_SELECT_S = "okMaps"; - - /** the indexes of the OK map files or null if all maps are OK */ - private int [] okMapNodeTypes; - - /** how many map files are read */ - private int nrofMapFilesRead = 0; - /** map cache -- in case last mm read the same map, use it without loading*/ - private static SimMap cachedMap = null; - /** names of the previously cached map's files (for hit comparison) */ - private static List cachedMapFiles = null; - - /** - * Creates a new MapBasedMovement based on a Settings object's settings. - * @param settings The Settings object where the settings are read from - */ - public MapBasedMovement(Settings settings) { - super(settings); - map = readMap(); + /** May a node choose to move back the same way it came at a crossing */ + protected boolean backAllowed; + /** map based movement model's settings namespace ({@value})*/ + public static final String MAP_BASE_MOVEMENT_NS = "MapBasedMovement"; + /** number of map files -setting id ({@value})*/ + public static final String NROF_FILES_S = "nrofMapFiles"; + /** map file -setting id ({@value})*/ + public static final String FILE_S = "mapFile"; + + /** + * Per node group setting for selecting map node types that are OK for + * this node group to traverse trough. Value must be a comma separated list + * of integers in range of [1,31]. Values reference to map file indexes + * (see {@link #FILE_S}). If setting is not defined, all map nodes are + * considered OK. + */ + public static final String MAP_SELECT_S = "okMaps"; + + /** the indexes of the OK map files or null if all maps are OK */ + private int [] okMapNodeTypes; + + /** how many map files are read */ + private int nrofMapFilesRead = 0; + /** map cache -- in case last mm read the same map, use it without loading*/ + private static SimMap cachedMap = null; + /** names of the previously cached map's files (for hit comparison) */ + private static List cachedMapFiles = null; + + /** + * Creates a new MapBasedMovement based on a Settings object's settings. + * @param settings The Settings object where the settings are read from + */ + public MapBasedMovement(Settings settings) { + super(settings); + map = readMap(); readOkMapNodeTypes(settings); maxPathLength = 100; minPathLength = 10; - backAllowed = false; - } - - /** - * Creates a new MapBasedMovement based on a Settings object's settings - * but with different SimMap - * @param settings The Settings object where the settings are read from - * @param newMap The SimMap to use - * @param nrofMaps How many map "files" are in the map - */ - public MapBasedMovement(Settings settings, SimMap newMap, int nrofMaps) { - super(settings); - map = newMap; - this.nrofMapFilesRead = nrofMaps; + backAllowed = false; + } + + /** + * Creates a new MapBasedMovement based on a Settings object's settings + * but with different SimMap + * @param settings The Settings object where the settings are read from + * @param newMap The SimMap to use + * @param nrofMaps How many map "files" are in the map + */ + public MapBasedMovement(Settings settings, SimMap newMap, int nrofMaps) { + super(settings); + map = newMap; + this.nrofMapFilesRead = nrofMaps; readOkMapNodeTypes(settings); maxPathLength = 100; minPathLength = 10; - backAllowed = false; - } - - /** - * Reads the OK map node types from settings - * @param settings The settings where the types are read - */ - private void readOkMapNodeTypes(Settings settings) { - if (settings.contains(MAP_SELECT_S)) { - this.okMapNodeTypes = settings.getCsvInts(MAP_SELECT_S); - for (int i : okMapNodeTypes) { - if (i < MapNode.MIN_TYPE || i > MapNode.MAX_TYPE) { - throw new SettingsError("Map type selection '" + i + - "' is out of range for setting " + - settings.getFullPropertyName(MAP_SELECT_S)); - } - if (i > nrofMapFilesRead) { - throw new SettingsError("Can't use map type selection '" + i - + "' for setting " + - settings.getFullPropertyName(MAP_SELECT_S) - + " because only " + nrofMapFilesRead + - " map files are read"); - } - } - } - else { - this.okMapNodeTypes = null; - } - } - - /** - * Copyconstructor. - * @param mbm The MapBasedMovement object to base the new object to - */ - protected MapBasedMovement(MapBasedMovement mbm) { - super(mbm); - this.okMapNodeTypes = mbm.okMapNodeTypes; + backAllowed = false; + } + + /** + * Reads the OK map node types from settings + * @param settings The settings where the types are read + */ + private void readOkMapNodeTypes(Settings settings) { + if (settings.contains(MAP_SELECT_S)) { + this.okMapNodeTypes = settings.getCsvInts(MAP_SELECT_S); + for (int i : okMapNodeTypes) { + if (i < MapNode.MIN_TYPE || i > MapNode.MAX_TYPE) { + throw new SettingsError("Map type selection '" + i + + "' is out of range for setting " + + settings.getFullPropertyName(MAP_SELECT_S)); + } + if (i > nrofMapFilesRead) { + throw new SettingsError("Can't use map type selection '" + i + + "' for setting " + + settings.getFullPropertyName(MAP_SELECT_S) + + " because only " + nrofMapFilesRead + + " map files are read"); + } + } + } + else { + this.okMapNodeTypes = null; + } + } + + /** + * Copyconstructor. + * @param mbm The MapBasedMovement object to base the new object to + */ + protected MapBasedMovement(MapBasedMovement mbm) { + super(mbm); + this.okMapNodeTypes = mbm.okMapNodeTypes; this.map = mbm.map; this.minPathLength = mbm.minPathLength; this.maxPathLength = mbm.maxPathLength; - this.backAllowed = mbm.backAllowed; - } - - /** - * Returns a (random) coordinate that is between two adjacent MapNodes - */ - @Override - public Coord getInitialLocation() { - List nodes = map.getNodes(); - MapNode n,n2; - Coord n2Location, nLocation, placement; - double dx, dy; - double rnd = rng.nextDouble(); - - // choose a random node (from OK types if such are defined) - do { - n = nodes.get(rng.nextInt(nodes.size())); - } while (okMapNodeTypes != null && !n.isType(okMapNodeTypes)); - - // choose a random neighbor of the selected node - n2 = n.getNeighbors().get(rng.nextInt(n.getNeighbors().size())); - - nLocation = n.getLocation(); - n2Location = n2.getLocation(); - - placement = n.getLocation().clone(); - - dx = rnd * (n2Location.getX() - nLocation.getX()); - dy = rnd * (n2Location.getY() - nLocation.getY()); - - placement.translate(dx, dy); // move coord from n towards n2 - - this.lastMapNode = n; - return placement; - } - - /** - * Returns map node types that are OK for this movement model in an array - * or null if all values are considered ok - * @return map node types that are OK for this movement model in an array - */ - protected int[] getOkMapNodeTypes() { - return okMapNodeTypes; - } - - @Override - public Path getPath() { - Path p = new Path(generateSpeed()); - MapNode curNode = lastMapNode; - MapNode prevNode = lastMapNode; - MapNode nextNode = null; - List neighbors; - Coord nextCoord; - - assert lastMapNode != null: "Tried to get a path before placement"; - - // start paths from current node - p.addWaypoint(curNode.getLocation()); - - int pathLength = rng.nextInt(maxPathLength-minPathLength) + - minPathLength; - - for (int i=0; i nodes = map.getNodes(); + MapNode n,n2; + Coord n2Location, nLocation, placement; + double dx, dy; + double rnd = rng.nextDouble(); + + // choose a random node (from OK types if such are defined) + do { + n = nodes.get(rng.nextInt(nodes.size())); + } while (okMapNodeTypes != null && !n.isType(okMapNodeTypes)); + + // choose a random neighbor of the selected node + n2 = n.getNeighbors().get(rng.nextInt(n.getNeighbors().size())); + + nLocation = n.getLocation(); + n2Location = n2.getLocation(); + + placement = n.getLocation().clone(); + + dx = rnd * (n2Location.getX() - nLocation.getX()); + dy = rnd * (n2Location.getY() - nLocation.getY()); + + placement.translate(dx, dy); // move coord from n towards n2 + + this.lastMapNode = n; + return placement; + } + + /** + * Returns map node types that are OK for this movement model in an array + * or null if all values are considered ok + * @return map node types that are OK for this movement model in an array + */ + protected int[] getOkMapNodeTypes() { + return okMapNodeTypes; + } + + @Override + public Path getPath() { + Path p = new Path(generateSpeed()); + MapNode curNode = lastMapNode; + MapNode prevNode = lastMapNode; + MapNode nextNode = null; + List neighbors; + Coord nextCoord; + + assert lastMapNode != null: "Tried to get a path before placement"; + + // start paths from current node + p.addWaypoint(curNode.getLocation()); + + int pathLength = rng.nextInt(maxPathLength-minPathLength) + + minPathLength; + + for (int i=0; i n2 = new Vector(neighbors); - if (!this.backAllowed) { - n2.remove(prevNode); // to prevent going back - } - - if (okMapNodeTypes != null) { //remove neighbor nodes that aren't ok - for (int j=0; j < n2.size(); ){ - if (!n2.get(j).isType(okMapNodeTypes)) { - n2.remove(j); - } - else { - j++; - } - } - } - - if (n2.size() == 0) { // only option is to go back - nextNode = prevNode; - } - else { // choose a random node from remaining neighbors - nextNode = n2.get(rng.nextInt(n2.size())); - } - - prevNode = curNode; - - nextCoord = nextNode.getLocation(); - curNode = nextNode; - - p.addWaypoint(nextCoord); - } - - lastMapNode = curNode; - - return p; - } - - /** - * Selects and returns a random node that is OK from a list of nodes. - * Whether node is OK, is determined by the okMapNodeTypes list. - * If okMapNodeTypes are defined, the given list must - * contain at least one OK node to prevent infinite looping. - * @param nodes The list of nodes to choose from. - * @return A random node from the list (that is OK if ok list is defined) - */ - protected MapNode selectRandomOkNode(List nodes) { - MapNode n; - do { - n = nodes.get(rng.nextInt(nodes.size())); - } while (okMapNodeTypes != null && !n.isType(okMapNodeTypes)); - - return n; - } - - /** - * Returns the SimMap this movement model uses - * @return The SimMap this movement model uses - */ - public SimMap getMap() { - return map; - } - - /** - * Reads a sim map from location set to the settings, mirrors the map and - * moves its upper left corner to origo. - * @return A new SimMap based on the settings - */ - private SimMap readMap() { - SimMap simMap; - Settings settings = new Settings(MAP_BASE_MOVEMENT_NS); - WKTMapReader r = new WKTMapReader(true); - - if (cachedMap == null) { - cachedMapFiles = new ArrayList(); // no cache present - } - else { // something in cache - // check out if previously asked map was asked again - SimMap cached = checkCache(settings); - if (cached != null) { - nrofMapFilesRead = cachedMapFiles.size(); - return cached; // we had right map cached -> return it - } - else { // no hit -> reset cache - cachedMapFiles = new ArrayList(); - cachedMap = null; - } - } - - try { - int nrofMapFiles = settings.getInt(NROF_FILES_S); - - for (int i = 1; i <= nrofMapFiles; i++ ) { - String pathFile = settings.getSetting(FILE_S + i); - cachedMapFiles.add(pathFile); - r.addPaths(new File(pathFile), i); - } - - nrofMapFilesRead = nrofMapFiles; - } catch (IOException e) { - throw new SimError(e.toString(),e); - } - - simMap = r.getMap(); - checkMapConnectedness(simMap.getNodes()); - // mirrors the map (y' = -y) and moves its upper left corner to origo - simMap.mirror(); - Coord offset = simMap.getMinBound().clone(); - simMap.translate(-offset.getX(), -offset.getY()); - checkCoordValidity(simMap.getNodes()); - - cachedMap = simMap; - return simMap; - } - - /** - * Checks that all map nodes can be reached from all other map nodes - * @param nodes The list of nodes to check - * @throws SettingsError if all map nodes are not connected - */ - private void checkMapConnectedness(List nodes) { - Set visited = new HashSet(); - Queue unvisited = new LinkedList(); - MapNode firstNode; - MapNode next = null; - + if (!this.backAllowed) { + n2.remove(prevNode); // to prevent going back + } + + if (okMapNodeTypes != null) { //remove neighbor nodes that aren't ok + for (int j=0; j < n2.size(); ){ + if (!n2.get(j).isType(okMapNodeTypes)) { + n2.remove(j); + } + else { + j++; + } + } + } + + if (n2.size() == 0) { // only option is to go back + nextNode = prevNode; + } + else { // choose a random node from remaining neighbors + nextNode = n2.get(rng.nextInt(n2.size())); + } + + prevNode = curNode; + + nextCoord = nextNode.getLocation(); + curNode = nextNode; + + p.addWaypoint(nextCoord); + } + + lastMapNode = curNode; + + return p; + } + + /** + * Selects and returns a random node that is OK from a list of nodes. + * Whether node is OK, is determined by the okMapNodeTypes list. + * If okMapNodeTypes are defined, the given list must + * contain at least one OK node to prevent infinite looping. + * @param nodes The list of nodes to choose from. + * @return A random node from the list (that is OK if ok list is defined) + */ + protected MapNode selectRandomOkNode(List nodes) { + MapNode n; + do { + n = nodes.get(rng.nextInt(nodes.size())); + } while (okMapNodeTypes != null && !n.isType(okMapNodeTypes)); + + return n; + } + + /** + * Returns the SimMap this movement model uses + * @return The SimMap this movement model uses + */ + public SimMap getMap() { + return map; + } + + /** + * Reads a sim map from location set to the settings, mirrors the map and + * moves its upper left corner to origo. + * @return A new SimMap based on the settings + */ + private SimMap readMap() { + SimMap simMap; + Settings settings = new Settings(MAP_BASE_MOVEMENT_NS); + WKTMapReader r = new WKTMapReader(true); + + if (cachedMap == null) { + cachedMapFiles = new ArrayList(); // no cache present + } + else { // something in cache + // check out if previously asked map was asked again + SimMap cached = checkCache(settings); + if (cached != null) { + nrofMapFilesRead = cachedMapFiles.size(); + return cached; // we had right map cached -> return it + } + else { // no hit -> reset cache + cachedMapFiles = new ArrayList(); + cachedMap = null; + } + } + + try { + int nrofMapFiles = settings.getInt(NROF_FILES_S); + + for (int i = 1; i <= nrofMapFiles; i++ ) { + String pathFile = settings.getSetting(FILE_S + i); + cachedMapFiles.add(pathFile); + r.addPaths(new File(pathFile), i); + } + + nrofMapFilesRead = nrofMapFiles; + } catch (IOException e) { + throw new SimError(e.toString(),e); + } + + simMap = r.getMap(); + checkMapConnectedness(simMap.getNodes()); + // mirrors the map (y' = -y) and moves its upper left corner to origo + simMap.mirror(); + Coord offset = simMap.getMinBound().clone(); + simMap.translate(-offset.getX(), -offset.getY()); + checkCoordValidity(simMap.getNodes()); + + cachedMap = simMap; + return simMap; + } + + /** + * Checks that all map nodes can be reached from all other map nodes + * @param nodes The list of nodes to check + * @throws SettingsError if all map nodes are not connected + */ + private void checkMapConnectedness(List nodes) { + Set visited = new HashSet(); + Queue unvisited = new LinkedList(); + MapNode firstNode; + MapNode next = null; + if (nodes.size() == 0) { throw new SimError("No map nodes in the given map"); } - + firstNode = nodes.get(0); - - visited.add(firstNode); - unvisited.addAll(firstNode.getNeighbors()); - - while ((next = unvisited.poll()) != null) { - visited.add(next); - for (MapNode n: next.getNeighbors()) { - if (!visited.contains(n) && ! unvisited.contains(n)) { - unvisited.add(n); - } - } - } - - if (visited.size() != nodes.size()) { // some node couldn't be reached - MapNode disconnected = null; - for (MapNode n : nodes) { // find an example node - if (!visited.contains(n)) { - disconnected = n; - break; - } - } - throw new SettingsError("SimMap is not fully connected. Only " + - visited.size() + " out of " + nodes.size() + " map nodes " + - "can be reached from " + firstNode + ". E.g. " + - disconnected + " can't be reached"); - } - } - - /** - * Checks that all coordinates of map nodes are within the min&max limits - * of the movement model - * @param nodes The list of nodes to check - * @throws SettingsError if some map node is out of bounds - */ - private void checkCoordValidity(List nodes) { - // Check that all map nodes are within world limits - for (MapNode n : nodes) { - double x = n.getLocation().getX(); - double y = n.getLocation().getY(); - if (x < 0 || x > getMaxX() || y < 0 || y > getMaxY()) { - throw new SettingsError("Map node " + n.getLocation() + - " is out of world bounds "+ - "(x: 0..." + getMaxX() + " y: 0..." + getMaxY() + ")"); - } - } - } - - /** - * Checks map cache if the requested map file(s) match to the cached - * sim map - * @param settings The Settings where map file names are found - * @return A cached map or null if the cached map didn't match - */ - private SimMap checkCache(Settings settings) { - int nrofMapFiles = settings.getInt(NROF_FILES_S); - - if (nrofMapFiles != cachedMapFiles.size() || cachedMap == null) { - return null; // wrong number of files - } - - for (int i = 1; i <= nrofMapFiles; i++ ) { - String pathFile = settings.getSetting(FILE_S + i); - if (!pathFile.equals(cachedMapFiles.get(i-1))) { - return null; // found wrong file name - } - } - - // all files matched -> return cached map - return cachedMap; - } - - @Override - public MapBasedMovement replicate() { - return new MapBasedMovement(this); + + visited.add(firstNode); + unvisited.addAll(firstNode.getNeighbors()); + + while ((next = unvisited.poll()) != null) { + visited.add(next); + for (MapNode n: next.getNeighbors()) { + if (!visited.contains(n) && ! unvisited.contains(n)) { + unvisited.add(n); + } + } + } + + if (visited.size() != nodes.size()) { // some node couldn't be reached + MapNode disconnected = null; + for (MapNode n : nodes) { // find an example node + if (!visited.contains(n)) { + disconnected = n; + break; + } + } + throw new SettingsError("SimMap is not fully connected. Only " + + visited.size() + " out of " + nodes.size() + " map nodes " + + "can be reached from " + firstNode + ". E.g. " + + disconnected + " can't be reached"); + } + } + + /** + * Checks that all coordinates of map nodes are within the min&max limits + * of the movement model + * @param nodes The list of nodes to check + * @throws SettingsError if some map node is out of bounds + */ + private void checkCoordValidity(List nodes) { + // Check that all map nodes are within world limits + for (MapNode n : nodes) { + double x = n.getLocation().getX(); + double y = n.getLocation().getY(); + if (x < 0 || x > getMaxX() || y < 0 || y > getMaxY()) { + throw new SettingsError("Map node " + n.getLocation() + + " is out of world bounds "+ + "(x: 0..." + getMaxX() + " y: 0..." + getMaxY() + ")"); + } + } + } + + /** + * Checks map cache if the requested map file(s) match to the cached + * sim map + * @param settings The Settings where map file names are found + * @return A cached map or null if the cached map didn't match + */ + private SimMap checkCache(Settings settings) { + int nrofMapFiles = settings.getInt(NROF_FILES_S); + + if (nrofMapFiles != cachedMapFiles.size() || cachedMap == null) { + return null; // wrong number of files + } + + for (int i = 1; i <= nrofMapFiles; i++ ) { + String pathFile = settings.getSetting(FILE_S + i); + if (!pathFile.equals(cachedMapFiles.get(i-1))) { + return null; // found wrong file name + } + } + + // all files matched -> return cached map + return cachedMap; + } + + @Override + public MapBasedMovement replicate() { + return new MapBasedMovement(this); } - + public Coord getLastLocation() { if (lastMapNode != null) { return lastMapNode.getLocation(); @@ -428,5 +428,5 @@ public void setLocation(Coord lastWaypoint) { public boolean isReady() { return true; } - -} + +} diff --git a/movement/MapRouteMovement.java b/movement/MapRouteMovement.java index da50422a7..46110709f 100644 --- a/movement/MapRouteMovement.java +++ b/movement/MapRouteMovement.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement; - +package movement; + import java.util.List; import core.SettingsError; @@ -12,128 +12,128 @@ import movement.map.MapRoute; import core.Coord; import core.Settings; - -/** - * Map based movement model that uses predetermined paths within the map area. - * Nodes using this model (can) stop on every route waypoint and find their - * way to next waypoint using {@link DijkstraPathFinder}. There can be - * different type of routes; see {@link #ROUTE_TYPE_S}. - */ -public class MapRouteMovement extends MapBasedMovement implements - SwitchableMovement { - - /** Per node group setting used for selecting a route file ({@value}) */ - public static final String ROUTE_FILE_S = "routeFile"; - /** - * Per node group setting used for selecting a route's type ({@value}). - * Integer value from {@link MapRoute} class. - */ - public static final String ROUTE_TYPE_S = "routeType"; - - /** + +/** + * Map based movement model that uses predetermined paths within the map area. + * Nodes using this model (can) stop on every route waypoint and find their + * way to next waypoint using {@link DijkstraPathFinder}. There can be + * different type of routes; see {@link #ROUTE_TYPE_S}. + */ +public class MapRouteMovement extends MapBasedMovement implements + SwitchableMovement { + + /** Per node group setting used for selecting a route file ({@value}) */ + public static final String ROUTE_FILE_S = "routeFile"; + /** + * Per node group setting used for selecting a route's type ({@value}). + * Integer value from {@link MapRoute} class. + */ + public static final String ROUTE_TYPE_S = "routeType"; + + /** * Per node group setting for selecting which stop (counting from 0 from - * the start of the route) should be the first one. By default, or if a + * the start of the route) should be the first one. By default, or if a * negative value is given, a random stop is selected. */ public static final String ROUTE_FIRST_STOP_S = "routeFirstStop"; - - /** the Dijkstra shortest path finder */ - private DijkstraPathFinder pathFinder; - - /** Prototype's reference to all routes read for the group */ - private List allRoutes = null; - /** next route's index to give by prototype */ - private Integer nextRouteIndex = null; + + /** the Dijkstra shortest path finder */ + private DijkstraPathFinder pathFinder; + + /** Prototype's reference to all routes read for the group */ + private List allRoutes = null; + /** next route's index to give by prototype */ + private Integer nextRouteIndex = null; /** Index of the first stop for a group of nodes (or -1 for random) */ - private int firstStopIndex = -1; - - /** Route of the movement model's instance */ - private MapRoute route; - - /** - * Creates a new movement model based on a Settings object's settings. - * @param settings The Settings object where the settings are read from - */ - public MapRouteMovement(Settings settings) { - super(settings); - String fileName = settings.getSetting(ROUTE_FILE_S); - int type = settings.getInt(ROUTE_TYPE_S); - allRoutes = MapRoute.readRoutes(fileName, type, getMap()); - nextRouteIndex = 0; + private int firstStopIndex = -1; + + /** Route of the movement model's instance */ + private MapRoute route; + + /** + * Creates a new movement model based on a Settings object's settings. + * @param settings The Settings object where the settings are read from + */ + public MapRouteMovement(Settings settings) { + super(settings); + String fileName = settings.getSetting(ROUTE_FILE_S); + int type = settings.getInt(ROUTE_TYPE_S); + allRoutes = MapRoute.readRoutes(fileName, type, getMap()); + nextRouteIndex = 0; pathFinder = new DijkstraPathFinder(getOkMapNodeTypes()); this.route = this.allRoutes.get(this.nextRouteIndex).replicate(); if (this.nextRouteIndex >= this.allRoutes.size()) { this.nextRouteIndex = 0; - } - + } + if (settings.contains(ROUTE_FIRST_STOP_S)) { this.firstStopIndex = settings.getInt(ROUTE_FIRST_STOP_S); if (this.firstStopIndex >= this.route.getNrofStops()) { - throw new SettingsError("Too high first stop's index (" + - this.firstStopIndex + ") for route with only " + + throw new SettingsError("Too high first stop's index (" + + this.firstStopIndex + ") for route with only " + this.route.getNrofStops() + " stops"); } - } - } - - /** - * Copyconstructor. Gives a route to the new movement model from the - * list of routes and randomizes the starting position. - * @param proto The MapRouteMovement prototype - */ - protected MapRouteMovement(MapRouteMovement proto) { - super(proto); - this.route = proto.allRoutes.get(proto.nextRouteIndex).replicate(); + } + } + + /** + * Copyconstructor. Gives a route to the new movement model from the + * list of routes and randomizes the starting position. + * @param proto The MapRouteMovement prototype + */ + protected MapRouteMovement(MapRouteMovement proto) { + super(proto); + this.route = proto.allRoutes.get(proto.nextRouteIndex).replicate(); this.firstStopIndex = proto.firstStopIndex; - + if (firstStopIndex < 0) { /* set a random starting position on the route */ - this.route.setNextIndex(rng.nextInt(route.getNrofStops()-1)); + this.route.setNextIndex(rng.nextInt(route.getNrofStops()-1)); } else { /* use the one defined in the config file */ this.route.setNextIndex(this.firstStopIndex); - } - - this.pathFinder = proto.pathFinder; - - proto.nextRouteIndex++; // give routes in order - if (proto.nextRouteIndex >= proto.allRoutes.size()) { - proto.nextRouteIndex = 0; - } - } - - @Override - public Path getPath() { - Path p = new Path(generateSpeed()); - MapNode to = route.nextStop(); - - List nodePath = pathFinder.getShortestPath(lastMapNode, to); - - // this assertion should never fire if the map is checked in read phase - assert nodePath.size() > 0 : "No path from " + lastMapNode + " to " + - to + ". The simulation map isn't fully connected"; - - for (MapNode node : nodePath) { // create a Path from the shortest path - p.addWaypoint(node.getLocation()); - } - - lastMapNode = to; - - return p; - } - + } + + this.pathFinder = proto.pathFinder; + + proto.nextRouteIndex++; // give routes in order + if (proto.nextRouteIndex >= proto.allRoutes.size()) { + proto.nextRouteIndex = 0; + } + } + + @Override + public Path getPath() { + Path p = new Path(generateSpeed()); + MapNode to = route.nextStop(); + + List nodePath = pathFinder.getShortestPath(lastMapNode, to); + + // this assertion should never fire if the map is checked in read phase + assert nodePath.size() > 0 : "No path from " + lastMapNode + " to " + + to + ". The simulation map isn't fully connected"; + + for (MapNode node : nodePath) { // create a Path from the shortest path + p.addWaypoint(node.getLocation()); + } + + lastMapNode = to; + + return p; + } + /** * Returns the first stop on the route - */ - @Override - public Coord getInitialLocation() { - if (lastMapNode == null) { + */ + @Override + public Coord getInitialLocation() { + if (lastMapNode == null) { lastMapNode = route.nextStop(); } - - return lastMapNode.getLocation().clone(); - } - + + return lastMapNode.getLocation().clone(); + } + @Override public Coord getLastLocation() { if (lastMapNode != null) { @@ -142,12 +142,12 @@ public Coord getLastLocation() { return null; } } - - - @Override - public MapRouteMovement replicate() { - return new MapRouteMovement(this); - } + + + @Override + public MapRouteMovement replicate() { + return new MapRouteMovement(this); + } /** * Returns the list of stops on the route @@ -155,5 +155,5 @@ public MapRouteMovement replicate() { */ public List getStops() { return route.getStops(); - } -} + } +} diff --git a/movement/MovementModel.java b/movement/MovementModel.java index 5c2968079..e033e491b 100644 --- a/movement/MovementModel.java +++ b/movement/MovementModel.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement; - +package movement; + import java.util.Random; import util.ActivenessHandler; @@ -15,200 +15,200 @@ import core.Settings; import core.SimClock; import core.SimError; - -/** - *

Superclass for all movement models. All subclasses must contain at least a - * constructor with one {@link Settings} parameter and also a copy-constructor. - * They must also implement the {@link #replicate()} method, which should return - * an instance of the movement model class with same parameters as the object - * (immutable fields can be shared, but mutable fields must be copied).

- *

To make a new movement model do something useful, also at least - * {@link #getInitialLocation()} and {@link #getPath()} are worthwhile to - * override.

- */ -public abstract class MovementModel { - /** node's speed CSV (min, max) -setting id ({@value})*/ - public static final String SPEED = "speed"; - /** node's wait time CSV (min, max) -setting id ({@value})*/ - public static final String WAIT_TIME = "waitTime"; - - /** default setting for speed distribution */ - public static final double[] DEF_SPEEDS = {1,1}; - /** default setting for wait time distribution */ - public static final double[] DEF_WAIT_TIMES = {0,0}; - - /** MovementModel namespace (where world size and rng seed settings - * are looked from ({@value})*/ - public static final String MOVEMENT_MODEL_NS = "MovementModel"; - /** world's size CSV (width, height) -setting id ({@value})*/ - public static final String WORLD_SIZE = "worldSize"; - /** movement models' rng seed -setting id ({@value})*/ - public static final String RNG_SEED = "rngSeed"; - - /** common rng for all movement models in the simulation */ - protected static Random rng; - + +/** + *

Superclass for all movement models. All subclasses must contain at least a + * constructor with one {@link Settings} parameter and also a copy-constructor. + * They must also implement the {@link #replicate()} method, which should return + * an instance of the movement model class with same parameters as the object + * (immutable fields can be shared, but mutable fields must be copied).

+ *

To make a new movement model do something useful, also at least + * {@link #getInitialLocation()} and {@link #getPath()} are worthwhile to + * override.

+ */ +public abstract class MovementModel { + /** node's speed CSV (min, max) -setting id ({@value})*/ + public static final String SPEED = "speed"; + /** node's wait time CSV (min, max) -setting id ({@value})*/ + public static final String WAIT_TIME = "waitTime"; + + /** default setting for speed distribution */ + public static final double[] DEF_SPEEDS = {1,1}; + /** default setting for wait time distribution */ + public static final double[] DEF_WAIT_TIMES = {0,0}; + + /** MovementModel namespace (where world size and rng seed settings + * are looked from ({@value})*/ + public static final String MOVEMENT_MODEL_NS = "MovementModel"; + /** world's size CSV (width, height) -setting id ({@value})*/ + public static final String WORLD_SIZE = "worldSize"; + /** movement models' rng seed -setting id ({@value})*/ + public static final String RNG_SEED = "rngSeed"; + + /** common rng for all movement models in the simulation */ + protected static Random rng; + /** DTNHost to which this movement model is attached */ protected DTNHost host; - - private ActivenessHandler ah; - - protected double minSpeed; - protected double maxSpeed; - protected double minWaitTime; - protected double maxWaitTime; - - private int maxX; + + private ActivenessHandler ah; + + protected double minSpeed; + protected double maxSpeed; + protected double minWaitTime; + protected double maxWaitTime; + + private int maxX; private int maxY; - - protected ModuleCommunicationBus comBus; - - // static initialization of all movement models' random number generator + + protected ModuleCommunicationBus comBus; + + // static initialization of all movement models' random number generator static { - DTNSim.registerForReset(MovementModel.class.getCanonicalName()); - reset(); - } - - /** - * Checks that the minimum setting is not bigger than the maximum and - * that both are positive - * @param name Name of the setting - * @param min The minimum setting - * @param max The maximum setting - */ - private static void checkMinAndMaxSetting(String name, - double min, double max) { - if (min < 0 || max < 0) { - throw new SimError("MovementModel." + name + " (in Settings)" + - " has a value less than zero ("+min+", "+max+")"); - } - if (min > max) { - throw new SimError("MovementModel." + name + " (in Settings)" + - " min is bigger than max ("+min+", "+max+")"); - } - } - - /** - * Empty constructor for testing purposes. - */ - public MovementModel() { - super(); - } - - /** - * Creates a new MovementModel based on a Settings object's settings. - * @param settings The Settings object where the settings are read from - */ - public MovementModel(Settings settings) { - double[] speeds; - double[] times; - - ah = new ActivenessHandler(settings); - - if (settings.contains(SPEED)) { - speeds = settings.getCsvDoubles(SPEED, 2); - } - else { - speeds = DEF_SPEEDS; - } - - minSpeed = speeds[0]; - maxSpeed = speeds[1]; - checkMinAndMaxSetting(SPEED,minSpeed,maxSpeed); - - if(settings.contains(WAIT_TIME)) { - times = settings.getCsvDoubles(WAIT_TIME, 2); - } - else { - times = DEF_WAIT_TIMES; - } - - minWaitTime = times[0]; - maxWaitTime = times[1]; - checkMinAndMaxSetting(WAIT_TIME,minWaitTime,maxWaitTime); - - settings.setNameSpace(MOVEMENT_MODEL_NS); - int [] worldSize = settings.getCsvInts(WORLD_SIZE,2); - this.maxX = worldSize[0]; - this.maxY = worldSize[1]; - - settings.restoreNameSpace(); - } - - /** - * Copyconstructor. Creates a new MovementModel based on the given - * prototype. - * @param mm The MovementModel prototype to base the new object to - */ - public MovementModel(MovementModel mm) { - this.maxSpeed = mm.maxSpeed; - this.minSpeed = mm.minSpeed; - this.maxWaitTime = mm.maxWaitTime; - this.minWaitTime = mm.minWaitTime; - this.maxX = mm.maxX; - this.maxY = mm.maxY; + DTNSim.registerForReset(MovementModel.class.getCanonicalName()); + reset(); + } + + /** + * Checks that the minimum setting is not bigger than the maximum and + * that both are positive + * @param name Name of the setting + * @param min The minimum setting + * @param max The maximum setting + */ + private static void checkMinAndMaxSetting(String name, + double min, double max) { + if (min < 0 || max < 0) { + throw new SimError("MovementModel." + name + " (in Settings)" + + " has a value less than zero ("+min+", "+max+")"); + } + if (min > max) { + throw new SimError("MovementModel." + name + " (in Settings)" + + " min is bigger than max ("+min+", "+max+")"); + } + } + + /** + * Empty constructor for testing purposes. + */ + public MovementModel() { + super(); + } + + /** + * Creates a new MovementModel based on a Settings object's settings. + * @param settings The Settings object where the settings are read from + */ + public MovementModel(Settings settings) { + double[] speeds; + double[] times; + + ah = new ActivenessHandler(settings); + + if (settings.contains(SPEED)) { + speeds = settings.getCsvDoubles(SPEED, 2); + } + else { + speeds = DEF_SPEEDS; + } + + minSpeed = speeds[0]; + maxSpeed = speeds[1]; + checkMinAndMaxSetting(SPEED,minSpeed,maxSpeed); + + if(settings.contains(WAIT_TIME)) { + times = settings.getCsvDoubles(WAIT_TIME, 2); + } + else { + times = DEF_WAIT_TIMES; + } + + minWaitTime = times[0]; + maxWaitTime = times[1]; + checkMinAndMaxSetting(WAIT_TIME,minWaitTime,maxWaitTime); + + settings.setNameSpace(MOVEMENT_MODEL_NS); + int [] worldSize = settings.getCsvInts(WORLD_SIZE,2); + this.maxX = worldSize[0]; + this.maxY = worldSize[1]; + + settings.restoreNameSpace(); + } + + /** + * Copyconstructor. Creates a new MovementModel based on the given + * prototype. + * @param mm The MovementModel prototype to base the new object to + */ + public MovementModel(MovementModel mm) { + this.maxSpeed = mm.maxSpeed; + this.minSpeed = mm.minSpeed; + this.maxWaitTime = mm.maxWaitTime; + this.minWaitTime = mm.minWaitTime; + this.maxX = mm.maxX; + this.maxY = mm.maxY; this.ah = mm.ah; - this.comBus = null; - } - - /** - * Returns the largest X coordinate value this model uses - * @return Maximum of X coordinate values - */ - public int getMaxX() { - return this.maxX; - } - - /** - * Returns the largest Y coordinate value this model uses - * @return Maximum of Y coordinate values - */ - public int getMaxY() { - return this.maxY; - } - - - /** - * Generates and returns a speed value between min and max of the - * {@link #WAIT_TIME} setting. - * @return A new speed between min and max values - */ - protected double generateSpeed() { - if (rng == null) { - return 1; - } - return (maxSpeed - minSpeed) * rng.nextDouble() + minSpeed; - } - - /** - * Generates and returns a suitable waiting time at the end of a path. - * (i.e. random variable whose value is between min and max of the - * {@link #WAIT_TIME} setting). - * @return The time as a double - */ - protected double generateWaitTime() { - if (rng == null) { - return 0; - } - return (maxWaitTime - minWaitTime) * rng.nextDouble() + - minWaitTime; - } - - /** - * Returns a new path by this movement model or null if no new path could - * be constructed at the moment (node should wait where it is). A new - * path should not be requested before the destination of the previous - * path has been reached. - * @return A new path or null - */ - public abstract Path getPath(); - - /** - * Returns a new initial placement for a node - * @return The initial coordinates for a node - */ - public abstract Coord getInitialLocation(); - + this.comBus = null; + } + + /** + * Returns the largest X coordinate value this model uses + * @return Maximum of X coordinate values + */ + public int getMaxX() { + return this.maxX; + } + + /** + * Returns the largest Y coordinate value this model uses + * @return Maximum of Y coordinate values + */ + public int getMaxY() { + return this.maxY; + } + + + /** + * Generates and returns a speed value between min and max of the + * {@link #WAIT_TIME} setting. + * @return A new speed between min and max values + */ + protected double generateSpeed() { + if (rng == null) { + return 1; + } + return (maxSpeed - minSpeed) * rng.nextDouble() + minSpeed; + } + + /** + * Generates and returns a suitable waiting time at the end of a path. + * (i.e. random variable whose value is between min and max of the + * {@link #WAIT_TIME} setting). + * @return The time as a double + */ + protected double generateWaitTime() { + if (rng == null) { + return 0; + } + return (maxWaitTime - minWaitTime) * rng.nextDouble() + + minWaitTime; + } + + /** + * Returns a new path by this movement model or null if no new path could + * be constructed at the moment (node should wait where it is). A new + * path should not be requested before the destination of the previous + * path has been reached. + * @return A new path or null + */ + public abstract Path getPath(); + + /** + * Returns a new initial placement for a node + * @return The initial coordinates for a node + */ + public abstract Coord getInitialLocation(); + /** * @return the host */ @@ -223,66 +223,66 @@ public void setHost(DTNHost host) { this.host = host; } - /** - * Returns true if this node is active at the moment (false if not) - * @return true if this node is active (false if not) - */ + /** + * Returns true if this node is active at the moment (false if not) + * @return true if this node is active (false if not) + */ public boolean isActive() { - /* TODO: add offset support */ - return ah.isActive(); - } - - /** - * Returns a sim time when the next path is available. This implementation - * returns a random time in future that is {@link #WAIT_TIME} from now. - * @return The sim time when node should ask the next time for a path - */ - public double nextPathAvailable() { - return SimClock.getTime() + generateWaitTime(); - } - + /* TODO: add offset support */ + return ah.isActive(); + } + + /** + * Returns a sim time when the next path is available. This implementation + * returns a random time in future that is {@link #WAIT_TIME} from now. + * @return The sim time when node should ask the next time for a path + */ + public double nextPathAvailable() { + return SimClock.getTime() + generateWaitTime(); + } + /** * Sets the module communication bus for this movement model * @param comBus The communications bus to set */ public void setComBus(ModuleCommunicationBus comBus) { - this.comBus = comBus; + this.comBus = comBus; } - + /** * Returns the module communication bus of this movement model (if any) * @return The communications bus or null if one is not set */ public ModuleCommunicationBus getComBus() { - return this.comBus; + return this.comBus; + } + + /** + * Returns simply the name of the movement model class + * @return the name of the movement model class + */ + public String toString() { + return this.getClass().getSimpleName(); + } + + /** + * Creates a replicate of the movement model. + * @return A new movement model with the same settings as this model + */ + public abstract MovementModel replicate(); + + /** + * Resets all static fields to default values + */ + public static void reset() { + Settings s = new Settings(MOVEMENT_MODEL_NS); + if (s.contains(RNG_SEED)) { + int seed = s.getInt(RNG_SEED); + rng = new Random(seed); + } + else { + rng = new Random(0); + } } - - /** - * Returns simply the name of the movement model class - * @return the name of the movement model class - */ - public String toString() { - return this.getClass().getSimpleName(); - } - - /** - * Creates a replicate of the movement model. - * @return A new movement model with the same settings as this model - */ - public abstract MovementModel replicate(); - - /** - * Resets all static fields to default values - */ - public static void reset() { - Settings s = new Settings(MOVEMENT_MODEL_NS); - if (s.contains(RNG_SEED)) { - int seed = s.getInt(RNG_SEED); - rng = new Random(seed); - } - else { - rng = new Random(0); - } - } - -} + +} diff --git a/movement/OfficeActivityMovement.java b/movement/OfficeActivityMovement.java index 1365d6ac7..0848558ac 100644 --- a/movement/OfficeActivityMovement.java +++ b/movement/OfficeActivityMovement.java @@ -1,286 +1,286 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import input.WKTReader; - -import java.io.File; -import java.util.LinkedList; -import java.util.List; - -import util.ParetoRNG; - -import movement.map.DijkstraPathFinder; -import movement.map.MapNode; -import movement.map.SimMap; -import core.Coord; -import core.Settings; -import core.SimClock; - -/** - * This class models movement at an office. If the node happens to be at some - * other location than the office, it first walks the shortest path to the - * office and then stays there until the end of the work day. A node has only - * works at one office. - * - * @author Frans Ekman - * - */ -public class OfficeActivityMovement extends MapBasedMovement implements - SwitchableMovement { - - private static final int WALKING_TO_OFFICE_MODE = 0; - private static final int AT_OFFICE_MODE = 1; - - public static final String WORK_DAY_LENGTH_SETTING = "workDayLength"; - public static final String NR_OF_OFFICES_SETTING = "nrOfOffices"; - - public static final String OFFICE_SIZE_SETTING = "officeSize"; - public static final String OFFICE_WAIT_TIME_PARETO_COEFF_SETTING = - "officeWaitTimeParetoCoeff"; - public static final String OFFICE_MIN_WAIT_TIME_SETTING = - "officeMinWaitTime"; - public static final String OFFICE_MAX_WAIT_TIME_SETTING = - "officeMaxWaitTime"; - public static final String OFFICE_LOCATIONS_FILE_SETTING = - "officeLocationsFile"; - - private static int nrOfOffices = 50; - - private int mode; - private int workDayLength; - private int startedWorkingTime; - private boolean ready;; - private DijkstraPathFinder pathFinder; - - private ParetoRNG paretoRNG; - - private int distance; - private double officeWaitTimeParetoCoeff; - private double officeMinWaitTime; - private double officeMaxWaitTime; - - private List allOffices; - - private Coord lastWaypoint; - private Coord officeLocation; - private Coord deskLocation; - - private boolean sittingAtDesk; - - /** - * OfficeActivityMovement constructor - * @param settings - */ - public OfficeActivityMovement(Settings settings) { - super(settings); - - workDayLength = settings.getInt(WORK_DAY_LENGTH_SETTING); - nrOfOffices = settings.getInt(NR_OF_OFFICES_SETTING); - - distance = settings.getInt(OFFICE_SIZE_SETTING); - officeWaitTimeParetoCoeff = settings.getDouble( - OFFICE_WAIT_TIME_PARETO_COEFF_SETTING); - officeMinWaitTime = settings.getDouble(OFFICE_MIN_WAIT_TIME_SETTING); - officeMaxWaitTime = settings.getDouble(OFFICE_MAX_WAIT_TIME_SETTING); - - startedWorkingTime = -1; - pathFinder = new DijkstraPathFinder(null); - mode = WALKING_TO_OFFICE_MODE; - - String officeLocationsFile = null; - try { - officeLocationsFile = settings.getSetting( - OFFICE_LOCATIONS_FILE_SETTING); - } catch (Throwable t) { - // Do nothing; - } - - if (officeLocationsFile == null) { - MapNode[] mapNodes = (MapNode[])getMap().getNodes(). - toArray(new MapNode[0]); - int officeIndex = rng.nextInt(mapNodes.length - 1) / - (mapNodes.length/nrOfOffices); - officeLocation = mapNodes[officeIndex].getLocation().clone(); - } else { - try { - allOffices = new LinkedList(); - List locationsRead = (new WKTReader()). - readPoints(new File(officeLocationsFile)); - for (Coord coord : locationsRead) { - SimMap map = getMap(); - Coord offset = map.getOffset(); - // mirror points if map data is mirrored - if (map.isMirrored()) { - coord.setLocation(coord.getX(), -coord.getY()); - } - coord.translate(offset.getX(), offset.getY()); - allOffices.add(coord); - } - officeLocation = allOffices.get( - rng.nextInt(allOffices.size())).clone(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - deskLocation = getRandomCoorinateInsideOffice(); - paretoRNG = new ParetoRNG(rng, officeWaitTimeParetoCoeff, - officeMinWaitTime, officeMaxWaitTime); - } - - /** - * Copyconstructor - * @param proto - */ - public OfficeActivityMovement(OfficeActivityMovement proto) { - super(proto); - this.workDayLength = proto.workDayLength; - startedWorkingTime = -1; - this.distance = proto.distance; - this.pathFinder = proto.pathFinder; - this.mode = proto.mode; - - if (proto.allOffices == null) { - MapNode[] mapNodes = (MapNode[])getMap().getNodes(). - toArray(new MapNode[0]); - int officeIndex = rng.nextInt(mapNodes.length - 1) / - (mapNodes.length/nrOfOffices); - officeLocation = mapNodes[officeIndex].getLocation().clone(); - } else { - this.allOffices = proto.allOffices; - officeLocation = allOffices.get( - rng.nextInt(allOffices.size())).clone(); - } - - officeWaitTimeParetoCoeff = proto.officeWaitTimeParetoCoeff; - officeMinWaitTime = proto.officeMinWaitTime; - officeMaxWaitTime = proto.officeMaxWaitTime; - - deskLocation = getRandomCoorinateInsideOffice(); - this.paretoRNG = proto.paretoRNG; - } - - public Coord getRandomCoorinateInsideOffice() { - double x_coord = officeLocation.getX() + - (0.5 - rng.nextDouble()) * distance; - if (x_coord > getMaxX()) { - x_coord = getMaxX(); - } else if (x_coord < 0) { - x_coord = 0; - } - double y_coord = officeLocation.getY() + - (0.5 - rng.nextDouble()) * distance; - if (y_coord > getMaxY()) { - y_coord = getMaxY(); - } else if (y_coord < 0) { - y_coord = 0; - } - return new Coord(x_coord, y_coord); - } - - @Override - public Coord getInitialLocation() { - double x = rng.nextDouble() * getMaxX(); - double y = rng.nextDouble() * getMaxY(); - Coord c = new Coord(x,y); - - this.lastWaypoint = c; - return c.clone(); - } - - @Override - public Path getPath() { - if (mode == WALKING_TO_OFFICE_MODE) { - // Try to find to the office - SimMap map = super.getMap(); - if (map == null) { - return null; - } - MapNode thisNode = map.getNodeByCoord(lastWaypoint); - MapNode destinationNode = map.getNodeByCoord(officeLocation); - List nodes = pathFinder.getShortestPath(thisNode, - destinationNode); - Path path = new Path(generateSpeed()); - for (MapNode node : nodes) { - path.addWaypoint(node.getLocation()); - } - lastWaypoint = officeLocation.clone(); - mode = AT_OFFICE_MODE; - return path; - } - - if (startedWorkingTime == -1) { - startedWorkingTime = SimClock.getIntTime(); - } - if (SimClock.getIntTime() - startedWorkingTime >= workDayLength) { - Path path = new Path(1); - path.addWaypoint(lastWaypoint.clone()); - ready = true; - return path; - } - Coord c; - if (sittingAtDesk) { - c = getRandomCoorinateInsideOffice(); - sittingAtDesk = false; - } else { - c = deskLocation.clone(); - sittingAtDesk = true; - } - - Path path = new Path(1); - path.addWaypoint(c); - return path; - } - - @Override - protected double generateWaitTime() { - int timeLeft = workDayLength - - (SimClock.getIntTime() - startedWorkingTime); - - int waitTime = (int)paretoRNG.getDouble(); - if (waitTime > timeLeft) { - return timeLeft; - } - return waitTime; - } - - @Override - public MapBasedMovement replicate() { - return new OfficeActivityMovement(this); - } - - /** - * @see SwitchableMovement - */ - public Coord getLastLocation() { - return lastWaypoint.clone(); - } - - /** - * @see SwitchableMovement - */ - public boolean isReady() { - return ready; - } - - /** - * @see SwitchableMovement - */ - public void setLocation(Coord lastWaypoint) { - this.lastWaypoint = lastWaypoint.clone(); - startedWorkingTime = -1; - ready = false; - mode = WALKING_TO_OFFICE_MODE; - } - - /** - * @return The location of the office - */ - public Coord getOfficeLocation() { - return officeLocation.clone(); - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import input.WKTReader; + +import java.io.File; +import java.util.LinkedList; +import java.util.List; + +import util.ParetoRNG; + +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import movement.map.SimMap; +import core.Coord; +import core.Settings; +import core.SimClock; + +/** + * This class models movement at an office. If the node happens to be at some + * other location than the office, it first walks the shortest path to the + * office and then stays there until the end of the work day. A node has only + * works at one office. + * + * @author Frans Ekman + * + */ +public class OfficeActivityMovement extends MapBasedMovement implements + SwitchableMovement { + + private static final int WALKING_TO_OFFICE_MODE = 0; + private static final int AT_OFFICE_MODE = 1; + + public static final String WORK_DAY_LENGTH_SETTING = "workDayLength"; + public static final String NR_OF_OFFICES_SETTING = "nrOfOffices"; + + public static final String OFFICE_SIZE_SETTING = "officeSize"; + public static final String OFFICE_WAIT_TIME_PARETO_COEFF_SETTING = + "officeWaitTimeParetoCoeff"; + public static final String OFFICE_MIN_WAIT_TIME_SETTING = + "officeMinWaitTime"; + public static final String OFFICE_MAX_WAIT_TIME_SETTING = + "officeMaxWaitTime"; + public static final String OFFICE_LOCATIONS_FILE_SETTING = + "officeLocationsFile"; + + private static int nrOfOffices = 50; + + private int mode; + private int workDayLength; + private int startedWorkingTime; + private boolean ready;; + private DijkstraPathFinder pathFinder; + + private ParetoRNG paretoRNG; + + private int distance; + private double officeWaitTimeParetoCoeff; + private double officeMinWaitTime; + private double officeMaxWaitTime; + + private List allOffices; + + private Coord lastWaypoint; + private Coord officeLocation; + private Coord deskLocation; + + private boolean sittingAtDesk; + + /** + * OfficeActivityMovement constructor + * @param settings + */ + public OfficeActivityMovement(Settings settings) { + super(settings); + + workDayLength = settings.getInt(WORK_DAY_LENGTH_SETTING); + nrOfOffices = settings.getInt(NR_OF_OFFICES_SETTING); + + distance = settings.getInt(OFFICE_SIZE_SETTING); + officeWaitTimeParetoCoeff = settings.getDouble( + OFFICE_WAIT_TIME_PARETO_COEFF_SETTING); + officeMinWaitTime = settings.getDouble(OFFICE_MIN_WAIT_TIME_SETTING); + officeMaxWaitTime = settings.getDouble(OFFICE_MAX_WAIT_TIME_SETTING); + + startedWorkingTime = -1; + pathFinder = new DijkstraPathFinder(null); + mode = WALKING_TO_OFFICE_MODE; + + String officeLocationsFile = null; + try { + officeLocationsFile = settings.getSetting( + OFFICE_LOCATIONS_FILE_SETTING); + } catch (Throwable t) { + // Do nothing; + } + + if (officeLocationsFile == null) { + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int officeIndex = rng.nextInt(mapNodes.length - 1) / + (mapNodes.length/nrOfOffices); + officeLocation = mapNodes[officeIndex].getLocation().clone(); + } else { + try { + allOffices = new LinkedList(); + List locationsRead = (new WKTReader()). + readPoints(new File(officeLocationsFile)); + for (Coord coord : locationsRead) { + SimMap map = getMap(); + Coord offset = map.getOffset(); + // mirror points if map data is mirrored + if (map.isMirrored()) { + coord.setLocation(coord.getX(), -coord.getY()); + } + coord.translate(offset.getX(), offset.getY()); + allOffices.add(coord); + } + officeLocation = allOffices.get( + rng.nextInt(allOffices.size())).clone(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + deskLocation = getRandomCoorinateInsideOffice(); + paretoRNG = new ParetoRNG(rng, officeWaitTimeParetoCoeff, + officeMinWaitTime, officeMaxWaitTime); + } + + /** + * Copyconstructor + * @param proto + */ + public OfficeActivityMovement(OfficeActivityMovement proto) { + super(proto); + this.workDayLength = proto.workDayLength; + startedWorkingTime = -1; + this.distance = proto.distance; + this.pathFinder = proto.pathFinder; + this.mode = proto.mode; + + if (proto.allOffices == null) { + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int officeIndex = rng.nextInt(mapNodes.length - 1) / + (mapNodes.length/nrOfOffices); + officeLocation = mapNodes[officeIndex].getLocation().clone(); + } else { + this.allOffices = proto.allOffices; + officeLocation = allOffices.get( + rng.nextInt(allOffices.size())).clone(); + } + + officeWaitTimeParetoCoeff = proto.officeWaitTimeParetoCoeff; + officeMinWaitTime = proto.officeMinWaitTime; + officeMaxWaitTime = proto.officeMaxWaitTime; + + deskLocation = getRandomCoorinateInsideOffice(); + this.paretoRNG = proto.paretoRNG; + } + + public Coord getRandomCoorinateInsideOffice() { + double x_coord = officeLocation.getX() + + (0.5 - rng.nextDouble()) * distance; + if (x_coord > getMaxX()) { + x_coord = getMaxX(); + } else if (x_coord < 0) { + x_coord = 0; + } + double y_coord = officeLocation.getY() + + (0.5 - rng.nextDouble()) * distance; + if (y_coord > getMaxY()) { + y_coord = getMaxY(); + } else if (y_coord < 0) { + y_coord = 0; + } + return new Coord(x_coord, y_coord); + } + + @Override + public Coord getInitialLocation() { + double x = rng.nextDouble() * getMaxX(); + double y = rng.nextDouble() * getMaxY(); + Coord c = new Coord(x,y); + + this.lastWaypoint = c; + return c.clone(); + } + + @Override + public Path getPath() { + if (mode == WALKING_TO_OFFICE_MODE) { + // Try to find to the office + SimMap map = super.getMap(); + if (map == null) { + return null; + } + MapNode thisNode = map.getNodeByCoord(lastWaypoint); + MapNode destinationNode = map.getNodeByCoord(officeLocation); + List nodes = pathFinder.getShortestPath(thisNode, + destinationNode); + Path path = new Path(generateSpeed()); + for (MapNode node : nodes) { + path.addWaypoint(node.getLocation()); + } + lastWaypoint = officeLocation.clone(); + mode = AT_OFFICE_MODE; + return path; + } + + if (startedWorkingTime == -1) { + startedWorkingTime = SimClock.getIntTime(); + } + if (SimClock.getIntTime() - startedWorkingTime >= workDayLength) { + Path path = new Path(1); + path.addWaypoint(lastWaypoint.clone()); + ready = true; + return path; + } + Coord c; + if (sittingAtDesk) { + c = getRandomCoorinateInsideOffice(); + sittingAtDesk = false; + } else { + c = deskLocation.clone(); + sittingAtDesk = true; + } + + Path path = new Path(1); + path.addWaypoint(c); + return path; + } + + @Override + protected double generateWaitTime() { + int timeLeft = workDayLength - + (SimClock.getIntTime() - startedWorkingTime); + + int waitTime = (int)paretoRNG.getDouble(); + if (waitTime > timeLeft) { + return timeLeft; + } + return waitTime; + } + + @Override + public MapBasedMovement replicate() { + return new OfficeActivityMovement(this); + } + + /** + * @see SwitchableMovement + */ + public Coord getLastLocation() { + return lastWaypoint.clone(); + } + + /** + * @see SwitchableMovement + */ + public boolean isReady() { + return ready; + } + + /** + * @see SwitchableMovement + */ + public void setLocation(Coord lastWaypoint) { + this.lastWaypoint = lastWaypoint.clone(); + startedWorkingTime = -1; + ready = false; + mode = WALKING_TO_OFFICE_MODE; + } + + /** + * @return The location of the office + */ + public Coord getOfficeLocation() { + return officeLocation.clone(); + } + +} diff --git a/movement/Path.java b/movement/Path.java index 1fc715dd3..01a4e5458 100644 --- a/movement/Path.java +++ b/movement/Path.java @@ -1,32 +1,32 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement; - +package movement; + import java.util.ArrayList; import java.util.List; import core.Coord; - -/** - * A Path between multiple Coordinates. - */ -public class Path { - /** coordinates of the path */ - private List coords; - /** speeds in the path legs */ - private List speeds; - private int nextWpIndex; - - /** - * Creates a path with zero speed. - */ - public Path() { - this.nextWpIndex = 0; - this.coords = new ArrayList(); - this.speeds = new ArrayList(1); - } + +/** + * A Path between multiple Coordinates. + */ +public class Path { + /** coordinates of the path */ + private List coords; + /** speeds in the path legs */ + private List speeds; + private int nextWpIndex; + + /** + * Creates a path with zero speed. + */ + public Path() { + this.nextWpIndex = 0; + this.coords = new ArrayList(); + this.speeds = new ArrayList(1); + } /** * Copy constructor. Creates a copy of this path with a shallow copy of @@ -38,104 +38,104 @@ public Path(Path path) { this.coords = new ArrayList((ArrayList)path.coords); this.speeds = new ArrayList((ArrayList)path.speeds); } - - /** - * Creates a path with constant speed - * @param speed The speed on the path - */ - public Path(double speed) { - this(); - setSpeed(speed); - } - - /** - * Sets a constant speed for the whole path. Any previously set speed(s) - * is discarded. - */ - public void setSpeed(double speed) { - this.speeds = new ArrayList(1); - speeds.add(speed); - } - - /** - * Returns a reference to the coordinates of this path - * @return coordinates of the path - */ - public List getCoords() { - return this.coords; - } - - /** - * Adds a new waypoint to the end of the path. - * @param wp The waypoint to add - */ - public void addWaypoint(Coord wp) { - assert this.speeds.size() <= 1 : "This method should be used only for" + - " paths with constant speed"; - this.coords.add(wp); - } - - /** - * Adds a new waypoint with a speed towards that waypoint - * @param wp The waypoint - * @param speed The speed towards that waypoint - */ - public void addWaypoint(Coord wp, double speed) { - this.coords.add(wp); - this.speeds.add(speed); - } - - /** - * Returns the next waypoint on this path - * @return the next waypoint - */ - public Coord getNextWaypoint() { - assert hasNext() : "Path didn't have " + (nextWpIndex+1) + ". waypoint"; - return coords.get(nextWpIndex++); - } - - /** - * Returns true if the path has more waypoints, false if not - * @return true if the path has more waypoints, false if not - */ - public boolean hasNext() { - return nextWpIndex < this.coords.size(); - } - - /** - * Returns the speed towards the next waypoint (asked with - * {@link #getNextWaypoint()}. - * @return the speed towards the next waypoint - */ - public double getSpeed() { - assert speeds.size() != 0 : "No speed set"; - assert nextWpIndex != 0 : "No waypoint asked"; - - if (speeds.size() == 1) { - return speeds.get(0); - } - else { - return speeds.get(nextWpIndex-1); - } - } - - /** - * Returns a string presentation of the path's coordinates - * @return Path as a string - */ - public String toString() { - String s =""; - for (int i=0, n=coords.size(); i 1) { - s += String.format("@%.2f ",speeds.get(i)); - } - } - return s; + + /** + * Creates a path with constant speed + * @param speed The speed on the path + */ + public Path(double speed) { + this(); + setSpeed(speed); } - + + /** + * Sets a constant speed for the whole path. Any previously set speed(s) + * is discarded. + */ + public void setSpeed(double speed) { + this.speeds = new ArrayList(1); + speeds.add(speed); + } + + /** + * Returns a reference to the coordinates of this path + * @return coordinates of the path + */ + public List getCoords() { + return this.coords; + } + + /** + * Adds a new waypoint to the end of the path. + * @param wp The waypoint to add + */ + public void addWaypoint(Coord wp) { + assert this.speeds.size() <= 1 : "This method should be used only for" + + " paths with constant speed"; + this.coords.add(wp); + } + + /** + * Adds a new waypoint with a speed towards that waypoint + * @param wp The waypoint + * @param speed The speed towards that waypoint + */ + public void addWaypoint(Coord wp, double speed) { + this.coords.add(wp); + this.speeds.add(speed); + } + + /** + * Returns the next waypoint on this path + * @return the next waypoint + */ + public Coord getNextWaypoint() { + assert hasNext() : "Path didn't have " + (nextWpIndex+1) + ". waypoint"; + return coords.get(nextWpIndex++); + } + + /** + * Returns true if the path has more waypoints, false if not + * @return true if the path has more waypoints, false if not + */ + public boolean hasNext() { + return nextWpIndex < this.coords.size(); + } + + /** + * Returns the speed towards the next waypoint (asked with + * {@link #getNextWaypoint()}. + * @return the speed towards the next waypoint + */ + public double getSpeed() { + assert speeds.size() != 0 : "No speed set"; + assert nextWpIndex != 0 : "No waypoint asked"; + + if (speeds.size() == 1) { + return speeds.get(0); + } + else { + return speeds.get(nextWpIndex-1); + } + } + + /** + * Returns a string presentation of the path's coordinates + * @return Path as a string + */ + public String toString() { + String s =""; + for (int i=0, n=coords.size(); i 1) { + s += String.format("@%.2f ",speeds.get(i)); + } + } + return s; + } + public List getSpeeds() { return this.speeds; - } -} + } +} diff --git a/movement/RandomWalk.java b/movement/RandomWalk.java index 9566b2472..ab5a34823 100644 --- a/movement/RandomWalk.java +++ b/movement/RandomWalk.java @@ -1,84 +1,84 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement; - +package movement; + import core.Coord; import core.Settings; /** * Random Walk movement model - * + * * @author Frans Ekman - */ -public class RandomWalk extends MovementModel implements SwitchableMovement { - + */ +public class RandomWalk extends MovementModel implements SwitchableMovement { + private Coord lastWaypoint; private double minDistance; - private double maxDistance; - - public RandomWalk(Settings settings) { + private double maxDistance; + + public RandomWalk(Settings settings) { super(settings); minDistance = 0; - maxDistance = 50; - } - - private RandomWalk(RandomWalk rwp) { + maxDistance = 50; + } + + private RandomWalk(RandomWalk rwp) { super(rwp); minDistance = rwp.minDistance; - maxDistance = rwp.maxDistance; - } - - /** - * Returns a possible (random) placement for a host - * @return Random position on the map - */ - @Override - public Coord getInitialLocation() { + maxDistance = rwp.maxDistance; + } + + /** + * Returns a possible (random) placement for a host + * @return Random position on the map + */ + @Override + public Coord getInitialLocation() { assert rng != null : "MovementModel not initialized!"; double x = rng.nextDouble() * getMaxX(); double y = rng.nextDouble() * getMaxY(); Coord c = new Coord(x,y); this.lastWaypoint = c; - return c; - } - - @Override - public Path getPath() { - Path p; - p = new Path(generateSpeed()); - p.addWaypoint(lastWaypoint.clone()); + return c; + } + + @Override + public Path getPath() { + Path p; + p = new Path(generateSpeed()); + p.addWaypoint(lastWaypoint.clone()); double maxX = getMaxX(); double maxY = getMaxY(); - + Coord c = null; while (true) { - + double angle = rng.nextDouble() * 2 * Math.PI; - double distance = minDistance + rng.nextDouble() * + double distance = minDistance + rng.nextDouble() * (maxDistance - minDistance); - + double x = lastWaypoint.getX() + distance * Math.cos(angle); double y = lastWaypoint.getY() + distance * Math.sin(angle); - + c = new Coord(x,y); - + if (x > 0 && y > 0 && x < maxX && y < maxY) { break; } - } - + } + p.addWaypoint(c); - - this.lastWaypoint = c; - return p; - } - - @Override - public RandomWalk replicate() { - return new RandomWalk(this); + + this.lastWaypoint = c; + return p; + } + + @Override + public RandomWalk replicate() { + return new RandomWalk(this); } public Coord getLastLocation() { @@ -91,5 +91,5 @@ public void setLocation(Coord lastWaypoint) { public boolean isReady() { return true; - } -} + } +} diff --git a/movement/RandomWaypoint.java b/movement/RandomWaypoint.java index e213e45a1..30103410b 100644 --- a/movement/RandomWaypoint.java +++ b/movement/RandomWaypoint.java @@ -1,65 +1,65 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement; - +package movement; + import core.Coord; import core.Settings; - -/** - * Random waypoint movement model. Creates zig-zag paths within the - * simulation area. - */ -public class RandomWaypoint extends MovementModel { - /** how many waypoints should there be per path */ - private static final int PATH_LENGTH = 1; - private Coord lastWaypoint; - - public RandomWaypoint(Settings settings) { - super(settings); - } - - protected RandomWaypoint(RandomWaypoint rwp) { - super(rwp); - } - - /** - * Returns a possible (random) placement for a host - * @return Random position on the map - */ - @Override - public Coord getInitialLocation() { - assert rng != null : "MovementModel not initialized!"; - Coord c = randomCoord(); - - this.lastWaypoint = c; - return c; - } - - @Override - public Path getPath() { - Path p; - p = new Path(generateSpeed()); - p.addWaypoint(lastWaypoint.clone()); - Coord c = lastWaypoint; - - for (int i=0; i nodePath = pathFinder.getShortestPath(lastMapNode, to); - - // this assertion should never fire if the map is checked in read phase - assert nodePath.size() > 0 : "No path from " + lastMapNode + " to " + - to + ". The simulation map isn't fully connected"; - - for (MapNode node : nodePath) { // create a Path from the shortest path - p.addWaypoint(node.getLocation()); - } - - lastMapNode = to; - - return p; - } - - @Override - public ShortestPathMapBasedMovement replicate() { - return new ShortestPathMapBasedMovement(this); + +/** + * Map based movement model that uses Dijkstra's algorithm to find shortest + * paths between two random map nodes and Points Of Interest + */ +public class ShortestPathMapBasedMovement extends MapBasedMovement implements + SwitchableMovement { + /** the Dijkstra shortest path finder */ + private DijkstraPathFinder pathFinder; + + /** Points Of Interest handler */ + private PointsOfInterest pois; + + /** + * Creates a new movement model based on a Settings object's settings. + * @param settings The Settings object where the settings are read from + */ + public ShortestPathMapBasedMovement(Settings settings) { + super(settings); + this.pathFinder = new DijkstraPathFinder(getOkMapNodeTypes()); + this.pois = new PointsOfInterest(getMap(), getOkMapNodeTypes(), + settings, rng); } - -} + + /** + * Copyconstructor. + * @param mbm The ShortestPathMapBasedMovement prototype to base + * the new object to + */ + protected ShortestPathMapBasedMovement(ShortestPathMapBasedMovement mbm) { + super(mbm); + this.pathFinder = mbm.pathFinder; + this.pois = mbm.pois; + } + + @Override + public Path getPath() { + Path p = new Path(generateSpeed()); + MapNode to = pois.selectDestination(); + + List nodePath = pathFinder.getShortestPath(lastMapNode, to); + + // this assertion should never fire if the map is checked in read phase + assert nodePath.size() > 0 : "No path from " + lastMapNode + " to " + + to + ". The simulation map isn't fully connected"; + + for (MapNode node : nodePath) { // create a Path from the shortest path + p.addWaypoint(node.getLocation()); + } + + lastMapNode = to; + + return p; + } + + @Override + public ShortestPathMapBasedMovement replicate() { + return new ShortestPathMapBasedMovement(this); + } + +} diff --git a/movement/StationaryMovement.java b/movement/StationaryMovement.java index d56c64bca..b0e9d95d8 100644 --- a/movement/StationaryMovement.java +++ b/movement/StationaryMovement.java @@ -1,70 +1,70 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement; - +package movement; + import core.Coord; import core.Settings; - -/** + +/** * A dummy stationary "movement" model where nodes do not move. - * Might be useful for simulations with only external connection events. - */ -public class StationaryMovement extends MovementModel { + * Might be useful for simulations with only external connection events. + */ +public class StationaryMovement extends MovementModel { /** Per node group setting for setting the location ({@value}) */ public static final String LOCATION_S = "nodeLocation"; private Coord loc; /** The location of the nodes */ - + /** * Creates a new movement model based on a Settings object's settings. * @param s The Settings object where the settings are read from - */ + */ public StationaryMovement(Settings s) { super(s); int coords[]; - + coords = s.getCsvInts(LOCATION_S, 2); this.loc = new Coord(coords[0],coords[1]); - } - + } + /** - * Copy constructor. + * Copy constructor. * @param sm The StationaryMovement prototype */ public StationaryMovement(StationaryMovement sm) { super(sm); this.loc = sm.loc; } - - /** - * Returns the only location of this movement model - * @return the only location of this movement model - */ - @Override - public Coord getInitialLocation() { - return loc; - } - - /** - * Returns a single coordinate path (using the only possible coordinate) - * @return a single coordinate path - */ - @Override - public Path getPath() { - Path p = new Path(0); - p.addWaypoint(loc); - return p; - } - - @Override - public double nextPathAvailable() { - return Double.MAX_VALUE; // no new paths available - } - - @Override - public StationaryMovement replicate() { - return new StationaryMovement(this); - } - -} + + /** + * Returns the only location of this movement model + * @return the only location of this movement model + */ + @Override + public Coord getInitialLocation() { + return loc; + } + + /** + * Returns a single coordinate path (using the only possible coordinate) + * @return a single coordinate path + */ + @Override + public Path getPath() { + Path p = new Path(0); + p.addWaypoint(loc); + return p; + } + + @Override + public double nextPathAvailable() { + return Double.MAX_VALUE; // no new paths available + } + + @Override + public StationaryMovement replicate() { + return new StationaryMovement(this); + } + +} diff --git a/movement/SwitchableMovement.java b/movement/SwitchableMovement.java index ea92ca5f3..9bc292cfb 100644 --- a/movement/SwitchableMovement.java +++ b/movement/SwitchableMovement.java @@ -1,37 +1,37 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import core.Coord; - -/** - - * Movement models to be used by ExtendedMovementModels should implement this - * interface - * - * @author Frans Ekman - */ -public interface SwitchableMovement { - - /** - * Tell the movement model what its current location is - * @param lastWaypoint - */ - public void setLocation(Coord lastWaypoint); - - /** - * Get the last location the getPath() of this movement model has returned - * @return the last location - */ - public Coord getLastLocation(); - - /** - * Checks if the movement model is finished doing its task and it's time to - * switch to the next movement model. The method should be called between - * getPath() calls. - * @return true if ready - */ - public boolean isReady(); -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; + +/** + + * Movement models to be used by ExtendedMovementModels should implement this + * interface + * + * @author Frans Ekman + */ +public interface SwitchableMovement { + + /** + * Tell the movement model what its current location is + * @param lastWaypoint + */ + public void setLocation(Coord lastWaypoint); + + /** + * Get the last location the getPath() of this movement model has returned + * @return the last location + */ + public Coord getLastLocation(); + + /** + * Checks if the movement model is finished doing its task and it's time to + * switch to the next movement model. The method should be called between + * getPath() calls. + * @return true if ready + */ + public boolean isReady(); +} diff --git a/movement/TransportMovement.java b/movement/TransportMovement.java index 372f99b1f..9801b7ab3 100644 --- a/movement/TransportMovement.java +++ b/movement/TransportMovement.java @@ -1,18 +1,18 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import core.Coord; - -/** - * MovementModels used for transportation should implement this interface - * - * @author Frans Ekman - */ -public interface TransportMovement extends SwitchableMovement { - - public void setNextRoute(Coord nodeLocation, Coord nodeDestination); - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; + +/** + * MovementModels used for transportation should implement this interface + * + * @author Frans Ekman + */ +public interface TransportMovement extends SwitchableMovement { + + public void setNextRoute(Coord nodeLocation, Coord nodeDestination); + +} diff --git a/movement/WorkingDayMovement.java b/movement/WorkingDayMovement.java index c6c56e738..7ab405423 100644 --- a/movement/WorkingDayMovement.java +++ b/movement/WorkingDayMovement.java @@ -1,180 +1,180 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package movement; - -import core.Coord; -import core.Settings; - -/** - * - * This movement model makes use of several other movement models to simulate - * movement with daily routines. People wake up in the morning, go to work, - * go shopping or similar activities in the evening and finally go home to - * sleep. - * - * @author Frans Ekman - */ -public class WorkingDayMovement extends ExtendedMovementModel { - - public static final String PROBABILITY_TO_OWN_CAR_SETTING = "ownCarProb"; - public static final String PROBABILITY_TO_GO_SHOPPING_SETTING = - "probGoShoppingAfterWork"; - - private BusTravellerMovement busTravellerMM; - private OfficeActivityMovement workerMM; - private HomeActivityMovement homeMM; - private EveningActivityMovement eveningActivityMovement; - private CarMovement carMM; - - private TransportMovement movementUsedForTransfers; - - private static final int BUS_TO_WORK_MODE = 0; - private static final int BUS_TO_HOME_MODE = 1; - private static final int BUS_TO_EVENING_ACTIVITY_MODE = 2; - - private static final int WORK_MODE = 3; - private static final int HOME_MODE = 4; - private static final int EVENING_ACTIVITY_MODE = 5; - - private int mode; - - private double ownCarProb; - private double doEveningActivityProb; - - /** - * Creates a new instance of WorkingDayMovement - * @param settings - */ - public WorkingDayMovement(Settings settings) { - super(settings); - busTravellerMM = new BusTravellerMovement(settings); - workerMM = new OfficeActivityMovement(settings); - homeMM = new HomeActivityMovement(settings); - eveningActivityMovement = new EveningActivityMovement(settings); - carMM = new CarMovement(settings); - ownCarProb = settings.getDouble(PROBABILITY_TO_OWN_CAR_SETTING); - if (rng.nextDouble() < ownCarProb) { - movementUsedForTransfers = carMM; - } else { - movementUsedForTransfers = busTravellerMM; - } - doEveningActivityProb = settings.getDouble( - PROBABILITY_TO_GO_SHOPPING_SETTING); - - setCurrentMovementModel(homeMM); - mode = HOME_MODE; - } - - /** - * Creates a new instance of WorkingDayMovement from a prototype - * @param proto - */ - public WorkingDayMovement(WorkingDayMovement proto) { - super(proto); - busTravellerMM = new BusTravellerMovement(proto.busTravellerMM); - workerMM = new OfficeActivityMovement(proto.workerMM); - homeMM = new HomeActivityMovement(proto.homeMM); - eveningActivityMovement = new EveningActivityMovement( - proto.eveningActivityMovement); - carMM = new CarMovement(proto.carMM); - - ownCarProb = proto.ownCarProb; - if (rng.nextDouble() < ownCarProb) { - movementUsedForTransfers = carMM; - } else { - movementUsedForTransfers = busTravellerMM; - } - doEveningActivityProb = proto.doEveningActivityProb; - - setCurrentMovementModel(homeMM); - mode = proto.mode; - } - - @Override - public boolean newOrders() { - switch (mode) { - case WORK_MODE: - if (workerMM.isReady()) { - setCurrentMovementModel(movementUsedForTransfers); - if (doEveningActivityProb > rng.nextDouble()) { - movementUsedForTransfers.setNextRoute( - workerMM.getOfficeLocation(), - eveningActivityMovement. - getShoppingLocationAndGetReady()); - mode = BUS_TO_EVENING_ACTIVITY_MODE; - } else { - movementUsedForTransfers.setNextRoute( - workerMM.getOfficeLocation(), - homeMM.getHomeLocation()); - mode = BUS_TO_HOME_MODE; - } - } - break; - case HOME_MODE: - if (homeMM.isReady()) { - setCurrentMovementModel(movementUsedForTransfers); - movementUsedForTransfers.setNextRoute(homeMM.getHomeLocation(), - workerMM.getOfficeLocation()); - mode = BUS_TO_WORK_MODE; - } - break; - case EVENING_ACTIVITY_MODE: - if (eveningActivityMovement.isReady()) { - setCurrentMovementModel(movementUsedForTransfers); - movementUsedForTransfers.setNextRoute(eveningActivityMovement. - getLastLocation(), homeMM.getHomeLocation()); - mode = BUS_TO_HOME_MODE; - } - break; - case BUS_TO_WORK_MODE: - if (movementUsedForTransfers.isReady()) { - setCurrentMovementModel(workerMM); - mode = WORK_MODE; - } - break; - case BUS_TO_HOME_MODE: - if (movementUsedForTransfers.isReady()) { - setCurrentMovementModel(homeMM); - mode = HOME_MODE; - } - break; - case BUS_TO_EVENING_ACTIVITY_MODE: - if (movementUsedForTransfers.isReady()) { - setCurrentMovementModel(eveningActivityMovement); - mode = EVENING_ACTIVITY_MODE; - } - break; - default: - break; - } - return true; - } - - @Override - public Coord getInitialLocation() { - Coord homeLoc = homeMM.getHomeLocation().clone(); - homeMM.setLocation(homeLoc); - return homeLoc; - } - - @Override - public MovementModel replicate() { - return new WorkingDayMovement(this); - } - - - public Coord getOfficeLocation() { - return workerMM.getOfficeLocation().clone(); - } - - public Coord getHomeLocation() { - return homeMM.getHomeLocation().clone(); - } - - public Coord getShoppingLocation() { - return eveningActivityMovement.getShoppingLocation().clone(); - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; +import core.Settings; + +/** + * + * This movement model makes use of several other movement models to simulate + * movement with daily routines. People wake up in the morning, go to work, + * go shopping or similar activities in the evening and finally go home to + * sleep. + * + * @author Frans Ekman + */ +public class WorkingDayMovement extends ExtendedMovementModel { + + public static final String PROBABILITY_TO_OWN_CAR_SETTING = "ownCarProb"; + public static final String PROBABILITY_TO_GO_SHOPPING_SETTING = + "probGoShoppingAfterWork"; + + private BusTravellerMovement busTravellerMM; + private OfficeActivityMovement workerMM; + private HomeActivityMovement homeMM; + private EveningActivityMovement eveningActivityMovement; + private CarMovement carMM; + + private TransportMovement movementUsedForTransfers; + + private static final int BUS_TO_WORK_MODE = 0; + private static final int BUS_TO_HOME_MODE = 1; + private static final int BUS_TO_EVENING_ACTIVITY_MODE = 2; + + private static final int WORK_MODE = 3; + private static final int HOME_MODE = 4; + private static final int EVENING_ACTIVITY_MODE = 5; + + private int mode; + + private double ownCarProb; + private double doEveningActivityProb; + + /** + * Creates a new instance of WorkingDayMovement + * @param settings + */ + public WorkingDayMovement(Settings settings) { + super(settings); + busTravellerMM = new BusTravellerMovement(settings); + workerMM = new OfficeActivityMovement(settings); + homeMM = new HomeActivityMovement(settings); + eveningActivityMovement = new EveningActivityMovement(settings); + carMM = new CarMovement(settings); + ownCarProb = settings.getDouble(PROBABILITY_TO_OWN_CAR_SETTING); + if (rng.nextDouble() < ownCarProb) { + movementUsedForTransfers = carMM; + } else { + movementUsedForTransfers = busTravellerMM; + } + doEveningActivityProb = settings.getDouble( + PROBABILITY_TO_GO_SHOPPING_SETTING); + + setCurrentMovementModel(homeMM); + mode = HOME_MODE; + } + + /** + * Creates a new instance of WorkingDayMovement from a prototype + * @param proto + */ + public WorkingDayMovement(WorkingDayMovement proto) { + super(proto); + busTravellerMM = new BusTravellerMovement(proto.busTravellerMM); + workerMM = new OfficeActivityMovement(proto.workerMM); + homeMM = new HomeActivityMovement(proto.homeMM); + eveningActivityMovement = new EveningActivityMovement( + proto.eveningActivityMovement); + carMM = new CarMovement(proto.carMM); + + ownCarProb = proto.ownCarProb; + if (rng.nextDouble() < ownCarProb) { + movementUsedForTransfers = carMM; + } else { + movementUsedForTransfers = busTravellerMM; + } + doEveningActivityProb = proto.doEveningActivityProb; + + setCurrentMovementModel(homeMM); + mode = proto.mode; + } + + @Override + public boolean newOrders() { + switch (mode) { + case WORK_MODE: + if (workerMM.isReady()) { + setCurrentMovementModel(movementUsedForTransfers); + if (doEveningActivityProb > rng.nextDouble()) { + movementUsedForTransfers.setNextRoute( + workerMM.getOfficeLocation(), + eveningActivityMovement. + getShoppingLocationAndGetReady()); + mode = BUS_TO_EVENING_ACTIVITY_MODE; + } else { + movementUsedForTransfers.setNextRoute( + workerMM.getOfficeLocation(), + homeMM.getHomeLocation()); + mode = BUS_TO_HOME_MODE; + } + } + break; + case HOME_MODE: + if (homeMM.isReady()) { + setCurrentMovementModel(movementUsedForTransfers); + movementUsedForTransfers.setNextRoute(homeMM.getHomeLocation(), + workerMM.getOfficeLocation()); + mode = BUS_TO_WORK_MODE; + } + break; + case EVENING_ACTIVITY_MODE: + if (eveningActivityMovement.isReady()) { + setCurrentMovementModel(movementUsedForTransfers); + movementUsedForTransfers.setNextRoute(eveningActivityMovement. + getLastLocation(), homeMM.getHomeLocation()); + mode = BUS_TO_HOME_MODE; + } + break; + case BUS_TO_WORK_MODE: + if (movementUsedForTransfers.isReady()) { + setCurrentMovementModel(workerMM); + mode = WORK_MODE; + } + break; + case BUS_TO_HOME_MODE: + if (movementUsedForTransfers.isReady()) { + setCurrentMovementModel(homeMM); + mode = HOME_MODE; + } + break; + case BUS_TO_EVENING_ACTIVITY_MODE: + if (movementUsedForTransfers.isReady()) { + setCurrentMovementModel(eveningActivityMovement); + mode = EVENING_ACTIVITY_MODE; + } + break; + default: + break; + } + return true; + } + + @Override + public Coord getInitialLocation() { + Coord homeLoc = homeMM.getHomeLocation().clone(); + homeMM.setLocation(homeLoc); + return homeLoc; + } + + @Override + public MovementModel replicate() { + return new WorkingDayMovement(this); + } + + + public Coord getOfficeLocation() { + return workerMM.getOfficeLocation().clone(); + } + + public Coord getHomeLocation() { + return homeMM.getHomeLocation().clone(); + } + + public Coord getShoppingLocation() { + return eveningActivityMovement.getShoppingLocation().clone(); + } + +} diff --git a/movement/map/DijkstraPathFinder.java b/movement/map/DijkstraPathFinder.java index d9ec88ee8..590b3e862 100644 --- a/movement/map/DijkstraPathFinder.java +++ b/movement/map/DijkstraPathFinder.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package movement.map; @@ -33,7 +33,7 @@ public class DijkstraPathFinder { private Map prevNodes; private int [] okMapNodes; - + /** * Constructor. * @param okMapNodes The map node types that are OK for paths or null if @@ -50,19 +50,19 @@ public DijkstraPathFinder(int [] okMapNodes) { */ private void initWith(MapNode node) { assert (okMapNodes != null ? node.isType(okMapNodes) : true); - + // create needed data structures - this.unvisited = new PriorityQueue(PQ_INIT_SIZE, + this.unvisited = new PriorityQueue(PQ_INIT_SIZE, new DistanceComparator()); this.visited = new HashSet(); this.prevNodes = new HashMap(); this.distances = new DistanceMap(); - + // set distance to source 0 and initialize unvisited queue this.distances.put(node, 0); this.unvisited.add(node); } - + /** * Finds and returns a shortest path between two map nodes * @param from The source of the path @@ -72,40 +72,40 @@ private void initWith(MapNode node) { */ public List getShortestPath(MapNode from, MapNode to) { List path = new LinkedList(); - + if (from.compareTo(to) == 0) { // source and destination are the same path.add(from); // return a list containing only source node return path; } - + initWith(from); MapNode node = null; - + // always take the node with shortest distance while ((node = unvisited.poll()) != null) { if (node == to) { break; // we found the destination -> no need to search further } - + visited.add(node); // mark the node as visited relax(node); // add/update neighbor nodes' distances } - + // now we either have the path or such path wasn't available if (node == to) { // found a path - path.add(0,to); - MapNode prev = prevNodes.get(to); - while (prev != from) { + path.add(0,to); + MapNode prev = prevNodes.get(to); + while (prev != from) { path.add(0, prev); // always put previous node to beginning prev = prevNodes.get(prev); } - + path.add(0, from); // finally put the source node to first node } - + return path; } - + /** * Relaxes the neighbors of a node (updates the shortest distances). * @param node The node whose neighbors are relaxed @@ -116,21 +116,21 @@ private void relax(MapNode node) { if (visited.contains(n)) { continue; // skip visited nodes } - + if (okMapNodes != null && !n.isType(okMapNodes)) { continue; // skip nodes that are not OK } - + // n node's distance from path's source node double nDist = nodeDist + getDistance(node, n); - + if (distances.get(n) > nDist) { // stored distance > found dist? prevNodes.put(n, node); setDistance(n, nDist); } } } - + /** * Sets the distance from source node to a node * @param n The node whose distance is set @@ -141,7 +141,7 @@ private void setDistance(MapNode n, double distance) { distances.put(n, distance); // update distance unvisited.add(n); // insert node to the new place in the queue } - + /** * Returns the (euclidean) distance between the two map nodes * @param from The first node @@ -151,13 +151,13 @@ private void setDistance(MapNode n, double distance) { private double getDistance(MapNode from, MapNode to) { return from.getLocation().distance(to.getLocation()); } - + /** * Comparator that compares two map nodes by their distance from * the source node. */ private class DistanceComparator implements Comparator { - + /** * Compares two map nodes by their distance from the source node * @return -1, 0 or 1 if node1's distance is smaller, equal to, or @@ -166,7 +166,7 @@ private class DistanceComparator implements Comparator { public int compare(MapNode node1, MapNode node2) { double dist1 = distances.get(node1); double dist2 = distances.get(node2); - + if (dist1 > dist2) { return 1; } @@ -178,20 +178,20 @@ else if (dist1 < dist2) { } } } - + /** - * Simple Map implementation for storing distances. + * Simple Map implementation for storing distances. */ private class DistanceMap { private HashMap map; - + /** * Constructor. Creates an empty distance map */ public DistanceMap() { - this.map = new HashMap(); + this.map = new HashMap(); } - + /** * Returns the distance to a node. If no distance value * is found, returns {@link DijkstraPathFinder#INFINITY} as the value. @@ -207,7 +207,7 @@ public double get(MapNode node) { return INFINITY; } } - + /** * Puts a new distance value for a map node * @param node The node @@ -216,7 +216,7 @@ public double get(MapNode node) { public void put(MapNode node, double distance) { map.put(node, distance); } - + /** * Returns a string representation of the map's contents * @return a string representation of the map's contents @@ -225,4 +225,4 @@ public String toString() { return map.toString(); } } -} \ No newline at end of file +} diff --git a/movement/map/MapNode.java b/movement/map/MapNode.java index c0f1f25d8..ff5f00878 100644 --- a/movement/map/MapNode.java +++ b/movement/map/MapNode.java @@ -1,146 +1,146 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement.map; - +package movement.map; + import java.util.List; import java.util.Vector; import core.Coord; import core.SettingsError; - -/** - * A node in a SimMap. Node has a location, 0-n neighbors that it is - * connected to and possibly a type identifier. - */ -public class MapNode implements Comparable { - /** Smallest valid type of a node: {@value}*/ - public static final int MIN_TYPE = 1; - /** Biggest valid type of a node: {@value} */ - public static final int MAX_TYPE = 31; - - - private Coord location; - private Vector neighbors; - // bit mask of map node's types or 0 if no type's are defined - private int type; - - /** - * Constructor. Creates a map node to a location. - * @param location The location of the node. - */ - public MapNode(Coord location) { - this.location = location; - this.neighbors = new Vector(); - type = 0; - } - - /** - * Adds a type indicator to this node - * @param type An integer from range [{@value MIN_TYPE}, {@value MAX_TYPE}] - */ - public void addType(int type) { - this.type |= typeToBitMask(type); - } - - /** - * Returns true if this node is of given type, false if none of node's - * type(s) match to given type or node doesn't have type at all - * @param type The type (integer from range [{@value MIN_TYPE}, - * {@value MAX_TYPE}]) - * @return True if this node is of given type - */ - public boolean isType(int type) { - if (this.type == 0) { - return false; - } - - return (this.type & typeToBitMask(type)) != 0; - } - - /** - * Returns true if the node's types match any of the given types - * @param types The types to check (array of values in range - * [{@value MIN_TYPE}, {@value MAX_TYPE}]) - * @return True if at least one of the types matched, false if none of the - * types matched - * @see #isType(int) - */ - public boolean isType(int[] types) { - for (int type : types) { - if (isType(type)) { - return true; - } - } - - return false; - } - - /** - * Converts type integer to a bit mask for setting & checking type - * @param type The type to convert - * @return A bit mask for the given type - * @throws SettingsError if the type is out of range - */ - private int typeToBitMask(int type) { - assert type >= MIN_TYPE && type <= MAX_TYPE : "Invalid node type "+type; - return 1 << type; // create the mask by bitwise shift - } - - /** - * Adds the node as this node's neighbour (unless the node is null) - * @param node The node to add or null for no action - */ - public void addNeighbor(MapNode node) { - if (node == null) { - return; - } - - addToList(node); // add the node to list - } - - /** - * Adds the node to list of neighbours unless it is already there or - * "neighbour" is this node - * @param node - */ - private void addToList(MapNode node) { - if (!this.neighbors.contains(node) && node != this) { - this.neighbors.add(node); - } - } - - /** - * Returns the location of the node - * @return the location of the node - */ - public Coord getLocation() { - return location; - } - - /** - * Returns the neighbors of this node. - * @return the neighbors in a list - */ - public List getNeighbors() { - return neighbors; - } - - /** - * Returns a String representation of the map node - * @return a String representation of the map node - */ - public String toString() { - return "N" + (type != 0 ? "t"+type : "") + "@"+this.location.toString(); - } - - /** + +/** + * A node in a SimMap. Node has a location, 0-n neighbors that it is + * connected to and possibly a type identifier. + */ +public class MapNode implements Comparable { + /** Smallest valid type of a node: {@value}*/ + public static final int MIN_TYPE = 1; + /** Biggest valid type of a node: {@value} */ + public static final int MAX_TYPE = 31; + + + private Coord location; + private Vector neighbors; + // bit mask of map node's types or 0 if no type's are defined + private int type; + + /** + * Constructor. Creates a map node to a location. + * @param location The location of the node. + */ + public MapNode(Coord location) { + this.location = location; + this.neighbors = new Vector(); + type = 0; + } + + /** + * Adds a type indicator to this node + * @param type An integer from range [{@value MIN_TYPE}, {@value MAX_TYPE}] + */ + public void addType(int type) { + this.type |= typeToBitMask(type); + } + + /** + * Returns true if this node is of given type, false if none of node's + * type(s) match to given type or node doesn't have type at all + * @param type The type (integer from range [{@value MIN_TYPE}, + * {@value MAX_TYPE}]) + * @return True if this node is of given type + */ + public boolean isType(int type) { + if (this.type == 0) { + return false; + } + + return (this.type & typeToBitMask(type)) != 0; + } + + /** + * Returns true if the node's types match any of the given types + * @param types The types to check (array of values in range + * [{@value MIN_TYPE}, {@value MAX_TYPE}]) + * @return True if at least one of the types matched, false if none of the + * types matched + * @see #isType(int) + */ + public boolean isType(int[] types) { + for (int type : types) { + if (isType(type)) { + return true; + } + } + + return false; + } + + /** + * Converts type integer to a bit mask for setting & checking type + * @param type The type to convert + * @return A bit mask for the given type + * @throws SettingsError if the type is out of range + */ + private int typeToBitMask(int type) { + assert type >= MIN_TYPE && type <= MAX_TYPE : "Invalid node type "+type; + return 1 << type; // create the mask by bitwise shift + } + + /** + * Adds the node as this node's neighbour (unless the node is null) + * @param node The node to add or null for no action + */ + public void addNeighbor(MapNode node) { + if (node == null) { + return; + } + + addToList(node); // add the node to list + } + + /** + * Adds the node to list of neighbours unless it is already there or + * "neighbour" is this node + * @param node + */ + private void addToList(MapNode node) { + if (!this.neighbors.contains(node) && node != this) { + this.neighbors.add(node); + } + } + + /** + * Returns the location of the node + * @return the location of the node + */ + public Coord getLocation() { + return location; + } + + /** + * Returns the neighbors of this node. + * @return the neighbors in a list + */ + public List getNeighbors() { + return neighbors; + } + + /** + * Returns a String representation of the map node + * @return a String representation of the map node + */ + public String toString() { + return "N" + (type != 0 ? "t"+type : "") + "@"+this.location.toString(); + } + + /** * Compares two map nodes by their coordinates - * @param o The other MapNode - */ - public int compareTo(MapNode o) { - return this.getLocation().compareTo((o).getLocation()); - } - -} + * @param o The other MapNode + */ + public int compareTo(MapNode o) { + return this.getLocation().compareTo((o).getLocation()); + } + +} diff --git a/movement/map/MapRoute.java b/movement/map/MapRoute.java index 3c51fcf1f..4a1eee0fb 100644 --- a/movement/map/MapRoute.java +++ b/movement/map/MapRoute.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement.map; - +package movement.map; + import input.WKTReader; import java.io.File; @@ -13,163 +13,163 @@ import core.Coord; import core.SettingsError; - -/** - * A route that consists of map nodes. There can be different kind of routes - * and the type is determined by the type parameter ({@value #CIRCULAR} - * or {@value #PINGPONG}). - */ -public class MapRoute { - /** Type of the route ID: circular ({@value}). - * After reaching the last node on path, the next node is the first node */ - public static final int CIRCULAR = 1; - /** Type of the route ID: ping-pong ({@value}). - * After last node on path, the direction on path is reversed */ - public static final int PINGPONG = 2; - - - private List stops; - private int type; // type of the route - private int index; // index of the previous returned map node - private boolean comingBack; - - /** - * Creates a new map route - * @param stops The stops of this route in a list - * @param type Type of the route (e.g. CIRCULAR or PINGPONG) - */ - public MapRoute(int type, List stops) { + +/** + * A route that consists of map nodes. There can be different kind of routes + * and the type is determined by the type parameter ({@value #CIRCULAR} + * or {@value #PINGPONG}). + */ +public class MapRoute { + /** Type of the route ID: circular ({@value}). + * After reaching the last node on path, the next node is the first node */ + public static final int CIRCULAR = 1; + /** Type of the route ID: ping-pong ({@value}). + * After last node on path, the direction on path is reversed */ + public static final int PINGPONG = 2; + + + private List stops; + private int type; // type of the route + private int index; // index of the previous returned map node + private boolean comingBack; + + /** + * Creates a new map route + * @param stops The stops of this route in a list + * @param type Type of the route (e.g. CIRCULAR or PINGPONG) + */ + public MapRoute(int type, List stops) { assert stops.size() > 0 : "Route needs stops"; - this.type = type; - this.stops = stops; - this.index = 0; - this.comingBack = false; - } - - /** - * Sets the next index for this route - * @param index The index to set - */ - public void setNextIndex(int index) { - if (index > stops.size()) { - index = stops.size(); - } - - this.index = index; - } - - /** - * Returns the number of stops on this route - * @return the number of stops on this route - */ - public int getNrofStops() { - return stops.size(); - } - + this.type = type; + this.stops = stops; + this.index = 0; + this.comingBack = false; + } + + /** + * Sets the next index for this route + * @param index The index to set + */ + public void setNextIndex(int index) { + if (index > stops.size()) { + index = stops.size(); + } + + this.index = index; + } + + /** + * Returns the number of stops on this route + * @return the number of stops on this route + */ + public int getNrofStops() { + return stops.size(); + } + public List getStops() { return this.stops; } - - /** - * Returns the next stop on the route (depending on the route mode) - * @return the next stop on the route - */ + + /** + * Returns the next stop on the route (depending on the route mode) + * @return the next stop on the route + */ public MapNode nextStop() { MapNode next = stops.get(index); - - if (comingBack) { - index--; // ping-pong coming back - } - else { - index++; - } - - if (index < 0) { // returned to beginning in ping-pong - comingBack = false; // start next round - index = 1; - } - - if (index >= stops.size()) { // reached last stop - if (type == PINGPONG) { - comingBack = true; - index = stops.size() - 1; // go next to prev to last stop - } - else { - index = 0; // circular goes back to square one - } - } - - return next; - } - - /** - * Returns a new route with the same settings - * @return a replicate of this route - */ - public MapRoute replicate() { - return new MapRoute(type, stops); - } - - public String toString() { - return ((type == CIRCULAR) ? "Circular" : "Ping-pong") + " route with "+ - getNrofStops() + " stops"; - } - - /** - * Reads routes from files defined in Settings - * @param fileName name of the file where to read routes - * @param type Type of the route - * @param map SimMap where corresponding map nodes are found - * @return A list of MapRoutes that were read - */ - public static List readRoutes(String fileName, int type, - SimMap map) { - List routes = new ArrayList(); - WKTReader reader = new WKTReader(); - List> coords; - File routeFile = null; - boolean mirror = map.isMirrored(); - double xOffset = map.getOffset().getX(); - double yOffset = map.getOffset().getY(); - - if (type != CIRCULAR && type != PINGPONG) { - throw new SettingsError("Invalid route type (" + type + ")"); - } - - try { - routeFile = new File(fileName); - coords = reader.readLines(routeFile); - } - catch (IOException ioe){ - throw new SettingsError("Couldn't read MapRoute-data file " + - fileName + " (cause: " + ioe.getMessage() + ")"); - } - - for (List l : coords) { - List nodes = new ArrayList(); - for (Coord c : l) { - // make coordinates match sim map data - if (mirror) { - c.setLocation(c.getX(), -c.getY()); - } - c.translate(xOffset, yOffset); - - MapNode node = map.getNodeByCoord(c); + + if (comingBack) { + index--; // ping-pong coming back + } + else { + index++; + } + + if (index < 0) { // returned to beginning in ping-pong + comingBack = false; // start next round + index = 1; + } + + if (index >= stops.size()) { // reached last stop + if (type == PINGPONG) { + comingBack = true; + index = stops.size() - 1; // go next to prev to last stop + } + else { + index = 0; // circular goes back to square one + } + } + + return next; + } + + /** + * Returns a new route with the same settings + * @return a replicate of this route + */ + public MapRoute replicate() { + return new MapRoute(type, stops); + } + + public String toString() { + return ((type == CIRCULAR) ? "Circular" : "Ping-pong") + " route with "+ + getNrofStops() + " stops"; + } + + /** + * Reads routes from files defined in Settings + * @param fileName name of the file where to read routes + * @param type Type of the route + * @param map SimMap where corresponding map nodes are found + * @return A list of MapRoutes that were read + */ + public static List readRoutes(String fileName, int type, + SimMap map) { + List routes = new ArrayList(); + WKTReader reader = new WKTReader(); + List> coords; + File routeFile = null; + boolean mirror = map.isMirrored(); + double xOffset = map.getOffset().getX(); + double yOffset = map.getOffset().getY(); + + if (type != CIRCULAR && type != PINGPONG) { + throw new SettingsError("Invalid route type (" + type + ")"); + } + + try { + routeFile = new File(fileName); + coords = reader.readLines(routeFile); + } + catch (IOException ioe){ + throw new SettingsError("Couldn't read MapRoute-data file " + + fileName + " (cause: " + ioe.getMessage() + ")"); + } + + for (List l : coords) { + List nodes = new ArrayList(); + for (Coord c : l) { + // make coordinates match sim map data + if (mirror) { + c.setLocation(c.getX(), -c.getY()); + } + c.translate(xOffset, yOffset); + + MapNode node = map.getNodeByCoord(c); if (node == null) { Coord orig = c.clone(); orig.translate(-xOffset, -yOffset); orig.setLocation(orig.getX(), -orig.getY()); - - throw new SettingsError("MapRoute in file " + routeFile + + + throw new SettingsError("MapRoute in file " + routeFile + " contained invalid coordinate " + c + " orig: " + - orig); - } - nodes.add(node); - } - - routes.add(new MapRoute(type, nodes)); - } - - return routes; - } -} + orig); + } + nodes.add(node); + } + + routes.add(new MapRoute(type, nodes)); + } + + return routes; + } +} diff --git a/movement/map/PointsOfInterest.java b/movement/map/PointsOfInterest.java index 925abc404..9cf626716 100644 --- a/movement/map/PointsOfInterest.java +++ b/movement/map/PointsOfInterest.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement.map; - +package movement.map; + import input.WKTReader; import java.io.File; @@ -18,206 +18,206 @@ import core.Coord; import core.Settings; import core.SettingsError; - -/** - * Handler for points of interest data. - */ -public class PointsOfInterest { - /** Points Of Interest settings namespace ({@value})*/ - public static final String POI_NS = "PointsOfInterest"; - /** Points Of Interest file path -prefix id ({@value})*/ - public static final String POI_FILE_S = "poiFile"; - - /** - * Per node group setting used for selecting POI groups and their - * probabilities ({@value}).
Syntax: - * poiGroupIndex1, groupSelectionProbability1, groupIndex2, prob2, - * etc...
- * Sum of probabilities must be less than or equal to one (1.0). If the sum - * is less than one, chance of getting a random MapPoint is - * 1-sum. - */ - public static final String POI_SELECT_S = "pois"; - /** map whose points all POIs are */ - private SimMap map; - /** map node types that are OK to visit */ - private int [] okMapNodeTypes; - /** list of all this POI instance's POI lists */ - private ArrayList> poiLists; - /** list of probabilites of choosing a POI group */ - private List> poiProbs; - /** (pseudo) random number generator */ - private Random rng; - - /** - * Constructor. - * @param parentMap The map whose MapNodes' subset the POIs are - * @param okMapNodeTypes Array of map node types that are OK to visit or - * null if all nodes are OK - * @param settings The Settings object where settings are read from - * @param rng The random number generator to use - */ - public PointsOfInterest(SimMap parentMap, int [] okMapNodeTypes, - Settings settings, Random rng) { - this.poiLists = new ArrayList>(); - this.poiProbs = new LinkedList>(); - this.map = parentMap; - this.okMapNodeTypes = okMapNodeTypes; - this.rng = rng; - readPois(settings); - } - - /** - * Selects a random destination from POIs or all MapNodes. Selecting among - * POI groups is done by their probabilities. If sum of their probabilities - * is less than 1.0 and the drawn random probability is bigger than the sum, - * a random MapNode is selected from the SimMap. - * @return A destination among POIs or all MapNodes - */ - public MapNode selectDestination() { - double random = rng.nextDouble(); - double acc = 0; - - for (Tuple t : poiProbs) { - acc += t.getKey(); - - if (acc > random) { - // get the lucky POI group - List pois = poiLists.get(t.getValue()); - // return a random POI from that group - return pois.get(rng.nextInt(pois.size())); - } - } - - // random was bigger than sum of probs -> return a random map node - // that is still OK (if OK node types are defined) - List allNodes = map.getNodes(); - MapNode node; - do { - node = allNodes.get(rng.nextInt(allNodes.size())); - } while (okMapNodeTypes != null && !node.isType(okMapNodeTypes)); - - return node; - } - - /** - * Reads POI selections and their probabilities from given Settings and - * stores them to poiLists and poiProbs. - * @param s The settings file where group specific settings are read - * @throws Settings error if there was an error while reading the file or - * some of the settings had invalid value(s). - */ - private void readPois(Settings s) { - Coord offset = map.getOffset(); - if (!s.contains(POI_SELECT_S)) { - return; // no POIs for this group - } - double[] groupPois = s.getCsvDoubles(POI_SELECT_S); - - // fully qualified setting name for error messages - String fqSetting = s.getFullPropertyName(POI_SELECT_S); - - if (groupPois.length % 2 != 0) { - throw new SettingsError("Invalid amount of POI selection-"+ - "probability values (" + groupPois.length + "). Must be " + - "divisable by 2 in " + fqSetting); - } - - // read POIs from the requested indexes and assign defined probabilites - for (int i=0; i 1.0) { - throw new SettingsError("Invalid probability value (" + prob + - ") for POI at index " + index + " in " + fqSetting); - } - - // check that there's no list of POIs for that index yet - if (index < poiLists.size() && poiLists.get(index) != null) { - throw new SettingsError("Duplicate definition for POI index " + - index + " in " + fqSetting); - } - - List nodes = readPoisOf(index, offset); - if (poiLists.size() <= index) { - // list too small -> fill with nulls up to index - for (int j = poiLists.size(); j <= index; j++) { - poiLists.add(j,null); - } - } - poiLists.set(index, nodes); - poiProbs.add(new Tuple(groupPois[i+1], index)); - } - - // check the sum of probabilites - double probSum = 0; - for (Tuple t : poiProbs) { - probSum += t.getKey(); - } - if (probSum > 1.0) { - throw new SettingsError("Sum of POI probabilities (" + - String.format("%.2f", probSum) + - ") exceeds 1.0 in " + fqSetting); - } - - } - - /** - * Reads POIs from a file {@value POI_FILE_S} + index defined - * in Settings' namespace {@value POI_NS}. - * @param index The index of the POI file - * @param offset Offset of map data - * @return A list of MapNodes read from the POI file - * @throws Settings error if there was an error while reading the file - * or some coordinate in POI-file didn't match any MapNode in the SimMap - */ - private List readPoisOf(int index, Coord offset) { - List nodes = new ArrayList(); - Settings fileSettings = new Settings(POI_NS); - WKTReader reader = new WKTReader(); - - File poiFile = null; - List coords = null; - try { - poiFile = new File(fileSettings.getSetting(POI_FILE_S + index)); - coords = reader.readPoints(poiFile); - } - catch (IOException ioe){ - throw new SettingsError("Couldn't read POI-data from file '" + - poiFile + "' defined in setting " + - fileSettings.getFullPropertyName(POI_FILE_S + index) + - " (cause: " + ioe.getMessage() + ")"); - } - - if (coords.size() == 0) { - throw new SettingsError("Read a POI group of size 0 from "+poiFile); - } - - for (Coord c : coords) { - if (map.isMirrored()) { // mirror POIs if map data is also mirrored - c.setLocation(c.getX(), -c.getY()); // flip around X axis - } - - // translate to match map data - c.translate(offset.getX(), offset.getY()); - - - MapNode node = map.getNodeByCoord(c); - if (node != null) { - if (okMapNodeTypes != null && !node.isType(okMapNodeTypes)) { - throw new SettingsError("POI " + node + " from file " + - poiFile + " is on a part of the map that is not "+ - "allowed for this movement model"); - } - nodes.add(node); - } - else { - throw new SettingsError("No MapNode in SimMap at location " + - c + " (after translation) from file " + poiFile); - } - } - - return nodes; - } -} + +/** + * Handler for points of interest data. + */ +public class PointsOfInterest { + /** Points Of Interest settings namespace ({@value})*/ + public static final String POI_NS = "PointsOfInterest"; + /** Points Of Interest file path -prefix id ({@value})*/ + public static final String POI_FILE_S = "poiFile"; + + /** + * Per node group setting used for selecting POI groups and their + * probabilities ({@value}).
Syntax: + * poiGroupIndex1, groupSelectionProbability1, groupIndex2, prob2, + * etc...
+ * Sum of probabilities must be less than or equal to one (1.0). If the sum + * is less than one, chance of getting a random MapPoint is + * 1-sum. + */ + public static final String POI_SELECT_S = "pois"; + /** map whose points all POIs are */ + private SimMap map; + /** map node types that are OK to visit */ + private int [] okMapNodeTypes; + /** list of all this POI instance's POI lists */ + private ArrayList> poiLists; + /** list of probabilites of choosing a POI group */ + private List> poiProbs; + /** (pseudo) random number generator */ + private Random rng; + + /** + * Constructor. + * @param parentMap The map whose MapNodes' subset the POIs are + * @param okMapNodeTypes Array of map node types that are OK to visit or + * null if all nodes are OK + * @param settings The Settings object where settings are read from + * @param rng The random number generator to use + */ + public PointsOfInterest(SimMap parentMap, int [] okMapNodeTypes, + Settings settings, Random rng) { + this.poiLists = new ArrayList>(); + this.poiProbs = new LinkedList>(); + this.map = parentMap; + this.okMapNodeTypes = okMapNodeTypes; + this.rng = rng; + readPois(settings); + } + + /** + * Selects a random destination from POIs or all MapNodes. Selecting among + * POI groups is done by their probabilities. If sum of their probabilities + * is less than 1.0 and the drawn random probability is bigger than the sum, + * a random MapNode is selected from the SimMap. + * @return A destination among POIs or all MapNodes + */ + public MapNode selectDestination() { + double random = rng.nextDouble(); + double acc = 0; + + for (Tuple t : poiProbs) { + acc += t.getKey(); + + if (acc > random) { + // get the lucky POI group + List pois = poiLists.get(t.getValue()); + // return a random POI from that group + return pois.get(rng.nextInt(pois.size())); + } + } + + // random was bigger than sum of probs -> return a random map node + // that is still OK (if OK node types are defined) + List allNodes = map.getNodes(); + MapNode node; + do { + node = allNodes.get(rng.nextInt(allNodes.size())); + } while (okMapNodeTypes != null && !node.isType(okMapNodeTypes)); + + return node; + } + + /** + * Reads POI selections and their probabilities from given Settings and + * stores them to poiLists and poiProbs. + * @param s The settings file where group specific settings are read + * @throws Settings error if there was an error while reading the file or + * some of the settings had invalid value(s). + */ + private void readPois(Settings s) { + Coord offset = map.getOffset(); + if (!s.contains(POI_SELECT_S)) { + return; // no POIs for this group + } + double[] groupPois = s.getCsvDoubles(POI_SELECT_S); + + // fully qualified setting name for error messages + String fqSetting = s.getFullPropertyName(POI_SELECT_S); + + if (groupPois.length % 2 != 0) { + throw new SettingsError("Invalid amount of POI selection-"+ + "probability values (" + groupPois.length + "). Must be " + + "divisable by 2 in " + fqSetting); + } + + // read POIs from the requested indexes and assign defined probabilites + for (int i=0; i 1.0) { + throw new SettingsError("Invalid probability value (" + prob + + ") for POI at index " + index + " in " + fqSetting); + } + + // check that there's no list of POIs for that index yet + if (index < poiLists.size() && poiLists.get(index) != null) { + throw new SettingsError("Duplicate definition for POI index " + + index + " in " + fqSetting); + } + + List nodes = readPoisOf(index, offset); + if (poiLists.size() <= index) { + // list too small -> fill with nulls up to index + for (int j = poiLists.size(); j <= index; j++) { + poiLists.add(j,null); + } + } + poiLists.set(index, nodes); + poiProbs.add(new Tuple(groupPois[i+1], index)); + } + + // check the sum of probabilites + double probSum = 0; + for (Tuple t : poiProbs) { + probSum += t.getKey(); + } + if (probSum > 1.0) { + throw new SettingsError("Sum of POI probabilities (" + + String.format("%.2f", probSum) + + ") exceeds 1.0 in " + fqSetting); + } + + } + + /** + * Reads POIs from a file {@value POI_FILE_S} + index defined + * in Settings' namespace {@value POI_NS}. + * @param index The index of the POI file + * @param offset Offset of map data + * @return A list of MapNodes read from the POI file + * @throws Settings error if there was an error while reading the file + * or some coordinate in POI-file didn't match any MapNode in the SimMap + */ + private List readPoisOf(int index, Coord offset) { + List nodes = new ArrayList(); + Settings fileSettings = new Settings(POI_NS); + WKTReader reader = new WKTReader(); + + File poiFile = null; + List coords = null; + try { + poiFile = new File(fileSettings.getSetting(POI_FILE_S + index)); + coords = reader.readPoints(poiFile); + } + catch (IOException ioe){ + throw new SettingsError("Couldn't read POI-data from file '" + + poiFile + "' defined in setting " + + fileSettings.getFullPropertyName(POI_FILE_S + index) + + " (cause: " + ioe.getMessage() + ")"); + } + + if (coords.size() == 0) { + throw new SettingsError("Read a POI group of size 0 from "+poiFile); + } + + for (Coord c : coords) { + if (map.isMirrored()) { // mirror POIs if map data is also mirrored + c.setLocation(c.getX(), -c.getY()); // flip around X axis + } + + // translate to match map data + c.translate(offset.getX(), offset.getY()); + + + MapNode node = map.getNodeByCoord(c); + if (node != null) { + if (okMapNodeTypes != null && !node.isType(okMapNodeTypes)) { + throw new SettingsError("POI " + node + " from file " + + poiFile + " is on a part of the map that is not "+ + "allowed for this movement model"); + } + nodes.add(node); + } + else { + throw new SettingsError("No MapNode in SimMap at location " + + c + " (after translation) from file " + poiFile); + } + } + + return nodes; + } +} diff --git a/movement/map/SimMap.java b/movement/map/SimMap.java index 6dcf26697..9e097b96e 100644 --- a/movement/map/SimMap.java +++ b/movement/map/SimMap.java @@ -1,167 +1,167 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package movement.map; - +package movement.map; + import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; import core.Coord; - -/** - * A simulation map for node movement. - */ -public class SimMap implements Serializable { - private Coord minBound; - private Coord maxBound; - /** list representation of the map for efficient list-returning */ - private ArrayList nodes; - /** hash map presentation of the map for efficient finding node by coord */ - private Map nodesMap; - /** offset of map translations */ - private Coord offset; - /** is this map data mirrored after reading */ - private boolean isMirrored; - - /** is re-hash needed before using hash mode (some coordinates changed) */ - private boolean needsRehash = false; - - public SimMap(Map nodes) { - this.offset = new Coord(0,0); - this.nodes = new ArrayList(nodes.values()); - this.nodesMap = nodes; - this.isMirrored = false; - setBounds(); - } - - /** - * Returns all the map nodes in a list - * @return all the map nodes in a list - */ - public List getNodes() { - return this.nodes; - } - - /** - * Returns a MapNode at given coordinates or null if there's no MapNode - * in the location of the coordinate - * @param c The coordinate - * @return The map node in that location or null if it doesn't exist - */ - public MapNode getNodeByCoord(Coord c) { - if (needsRehash) { // some coordinates have changed after creating hash - nodesMap.clear(); - for (MapNode node : getNodes()) { - nodesMap.put(node.getLocation(), node); // re-hash - } - } - - return nodesMap.get(c); - } - - /** - * Returns the upper left corner coordinate of the map - * @return the upper left corner coordinate of the map - */ - public Coord getMinBound() { - return this.minBound; - } - - /** - * Returns the lower right corner coordinate of the map - * @return the lower right corner coordinate of the map - */ - public Coord getMaxBound() { - return this.maxBound; - } - - /** - * Returns the offset that has been caused by translates made to - * this map (does NOT take into account mirroring). - * @return The current offset - */ - public Coord getOffset() { - return this.offset; - } - - /** - * Returns true if this map has been mirrored after reading - * @return true if this map has been mirrored after reading - * @see #mirror() - */ - public boolean isMirrored() { - return this.isMirrored; - } - - /** - * Translate whole map by dx and dy - * @param dx The amount to translate X coordinates - * @param dy the amount to translate Y coordinates - */ - public void translate(double dx, double dy) { - for (MapNode n : nodes) { - n.getLocation().translate(dx, dy); - } - - minBound.translate(dx, dy); - maxBound.translate(dx, dy); - offset.translate(dx, dy); - - needsRehash = true; - } - - /** - * Mirrors all map coordinates around X axis (x'=x, y'=-y). - */ - public void mirror() { - assert !isMirrored : "Map data already mirrored"; - - Coord c; - for (MapNode n : nodes) { - c=n.getLocation(); - c.setLocation(c.getX(), -c.getY()); - } - setBounds(); - this.isMirrored = true; - needsRehash = true; - } - - /** - * Updates the min & max bounds to conform to the values of the map nodes. - */ - private void setBounds() { - double minX, minY, maxX, maxY; - Coord c; - minX = minY = Double.MAX_VALUE; - maxX = maxY = -Double.MAX_VALUE; - - for (MapNode n : nodes) { - c = n.getLocation(); - if (c.getX() < minX) { - minX = c.getX(); - } - if (c.getX() > maxX) { - maxX = c.getX(); - } - if (c.getY() < minY) { - minY = c.getY(); - } - if (c.getY() > maxY) { - maxY = c.getY(); - } - } - minBound = new Coord(minX, minY); - maxBound = new Coord(maxX, maxY); - } - - /** - * Returns a String representation of the map - * @return a String representation of the map - */ - public String toString() { - return this.nodes.toString(); - } -} \ No newline at end of file + +/** + * A simulation map for node movement. + */ +public class SimMap implements Serializable { + private Coord minBound; + private Coord maxBound; + /** list representation of the map for efficient list-returning */ + private ArrayList nodes; + /** hash map presentation of the map for efficient finding node by coord */ + private Map nodesMap; + /** offset of map translations */ + private Coord offset; + /** is this map data mirrored after reading */ + private boolean isMirrored; + + /** is re-hash needed before using hash mode (some coordinates changed) */ + private boolean needsRehash = false; + + public SimMap(Map nodes) { + this.offset = new Coord(0,0); + this.nodes = new ArrayList(nodes.values()); + this.nodesMap = nodes; + this.isMirrored = false; + setBounds(); + } + + /** + * Returns all the map nodes in a list + * @return all the map nodes in a list + */ + public List getNodes() { + return this.nodes; + } + + /** + * Returns a MapNode at given coordinates or null if there's no MapNode + * in the location of the coordinate + * @param c The coordinate + * @return The map node in that location or null if it doesn't exist + */ + public MapNode getNodeByCoord(Coord c) { + if (needsRehash) { // some coordinates have changed after creating hash + nodesMap.clear(); + for (MapNode node : getNodes()) { + nodesMap.put(node.getLocation(), node); // re-hash + } + } + + return nodesMap.get(c); + } + + /** + * Returns the upper left corner coordinate of the map + * @return the upper left corner coordinate of the map + */ + public Coord getMinBound() { + return this.minBound; + } + + /** + * Returns the lower right corner coordinate of the map + * @return the lower right corner coordinate of the map + */ + public Coord getMaxBound() { + return this.maxBound; + } + + /** + * Returns the offset that has been caused by translates made to + * this map (does NOT take into account mirroring). + * @return The current offset + */ + public Coord getOffset() { + return this.offset; + } + + /** + * Returns true if this map has been mirrored after reading + * @return true if this map has been mirrored after reading + * @see #mirror() + */ + public boolean isMirrored() { + return this.isMirrored; + } + + /** + * Translate whole map by dx and dy + * @param dx The amount to translate X coordinates + * @param dy the amount to translate Y coordinates + */ + public void translate(double dx, double dy) { + for (MapNode n : nodes) { + n.getLocation().translate(dx, dy); + } + + minBound.translate(dx, dy); + maxBound.translate(dx, dy); + offset.translate(dx, dy); + + needsRehash = true; + } + + /** + * Mirrors all map coordinates around X axis (x'=x, y'=-y). + */ + public void mirror() { + assert !isMirrored : "Map data already mirrored"; + + Coord c; + for (MapNode n : nodes) { + c=n.getLocation(); + c.setLocation(c.getX(), -c.getY()); + } + setBounds(); + this.isMirrored = true; + needsRehash = true; + } + + /** + * Updates the min & max bounds to conform to the values of the map nodes. + */ + private void setBounds() { + double minX, minY, maxX, maxY; + Coord c; + minX = minY = Double.MAX_VALUE; + maxX = maxY = -Double.MAX_VALUE; + + for (MapNode n : nodes) { + c = n.getLocation(); + if (c.getX() < minX) { + minX = c.getX(); + } + if (c.getX() > maxX) { + maxX = c.getX(); + } + if (c.getY() < minY) { + minY = c.getY(); + } + if (c.getY() > maxY) { + maxY = c.getY(); + } + } + minBound = new Coord(minX, minY); + maxBound = new Coord(maxX, maxY); + } + + /** + * Returns a String representation of the map + * @return a String representation of the map + */ + public String toString() { + return this.nodes.toString(); + } +} diff --git a/movement/map/package.html b/movement/map/package.html index 379663b48..212593395 100644 --- a/movement/map/package.html +++ b/movement/map/package.html @@ -1,9 +1,9 @@ - - - - -Sub package for MapBasedMovement movement model's (and its sub classes) -helper classes. - - - \ No newline at end of file + + + + +Sub package for MapBasedMovement movement model's (and its sub classes) +helper classes. + + + diff --git a/movement/package.html b/movement/package.html index 8ca20683a..f13cc530d 100644 --- a/movement/package.html +++ b/movement/package.html @@ -1,18 +1,18 @@ - - - - -Contains different movement models and related classes for the simulator. -All movement models have to be in this package and must extend the -{@link movement.MovementModel} class so they can be dynamically -loaded to the simulator. The classes to load can be specified trough -{@link core.Settings} class' settings source. See MovementModel class and -classes extending it for details about the settings. - - -Complex movement models can store their other -classes (the ones that don't extend MovementModel class) to sub packages. - - - - \ No newline at end of file + + + + +Contains different movement models and related classes for the simulator. +All movement models have to be in this package and must extend the +{@link movement.MovementModel} class so they can be dynamically +loaded to the simulator. The classes to load can be specified trough +{@link core.Settings} class' settings source. See MovementModel class and +classes extending it for details about the settings. + + +Complex movement models can store their other +classes (the ones that don't extend MovementModel class) to sub packages. + + + + diff --git a/report/AdjacencyGraphvizReport.java b/report/AdjacencyGraphvizReport.java index 9e7afd1d0..55a35f8f7 100644 --- a/report/AdjacencyGraphvizReport.java +++ b/report/AdjacencyGraphvizReport.java @@ -1,121 +1,121 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import java.util.Collection; import java.util.HashMap; import core.ConnectionListener; import core.DTNHost; - -/** + +/** * Generates Graphviz compatible graph from connections. - * Connections that happen during the warm up period are ignored. - */ -public class AdjacencyGraphvizReport extends Report implements ConnectionListener { - /** Name of the graphviz report ({@value})*/ - public static final String GRAPH_NAME = "adjgraph"; - - private String HOST_DELIM = "<->"; // used in toString() - private HashMap cons; - private Collection allHosts; - - /** - * Constructor. - */ - public AdjacencyGraphvizReport() { - this.allHosts = null; - init(); - } - - protected void init() { - super.init(); - this.cons = new HashMap(); - } - - + * Connections that happen during the warm up period are ignored. + */ +public class AdjacencyGraphvizReport extends Report implements ConnectionListener { + /** Name of the graphviz report ({@value})*/ + public static final String GRAPH_NAME = "adjgraph"; + + private String HOST_DELIM = "<->"; // used in toString() + private HashMap cons; + private Collection allHosts; + + /** + * Constructor. + */ + public AdjacencyGraphvizReport() { + this.allHosts = null; + init(); + } + + protected void init() { + super.init(); + this.cons = new HashMap(); + } + + public void hostsConnected(DTNHost host1, DTNHost host2) { if (isWarmup()) { return; } - - newEvent(); - ConnectionInfo ci = cons.get(host1+HOST_DELIM+host2); - - if (ci == null) { - cons.put(host1+HOST_DELIM+host2, new ConnectionInfo(host1,host2)); - } - else { - ci.nrofConnections++; - } - } - - // Nothing to do here.. - public void hostsDisconnected(DTNHost host1, DTNHost host2) {} - - /** - * Sets all hosts that should be in the graph at least once - * @param hosts Collection of hosts - */ - public void setAllHosts(Collection hosts) { - this.allHosts = hosts; - } - - public void done() { - write("graph " + GRAPH_NAME + " {"); - setPrefix("\t"); // indent following lines by one tab - - for (ConnectionInfo ci : cons.values()) { - int weight = ci.nrofConnections; - write(ci.h1 + "--" + ci.h2 + " [weight=" + weight + "];"); - } - - // mention all hosts in the graph at least once - if (this.allHosts != null) { - for (DTNHost h : allHosts) { - write(h+ ";"); - } - } - - setPrefix(""); // don't indent anymore - write("}"); - - super.done(); - } - - /** - * Private class stores information of the connected hosts - * and nrof times they have connected. - */ - private class ConnectionInfo { - private DTNHost h1; - private DTNHost h2; - private int nrofConnections; - - public ConnectionInfo(DTNHost h1, DTNHost h2) { - this.h1 = h1; - this.h2 = h2; - this.nrofConnections = 1; - } - + + newEvent(); + ConnectionInfo ci = cons.get(host1+HOST_DELIM+host2); + + if (ci == null) { + cons.put(host1+HOST_DELIM+host2, new ConnectionInfo(host1,host2)); + } + else { + ci.nrofConnections++; + } + } + + // Nothing to do here.. + public void hostsDisconnected(DTNHost host1, DTNHost host2) {} + + /** + * Sets all hosts that should be in the graph at least once + * @param hosts Collection of hosts + */ + public void setAllHosts(Collection hosts) { + this.allHosts = hosts; + } + + public void done() { + write("graph " + GRAPH_NAME + " {"); + setPrefix("\t"); // indent following lines by one tab + + for (ConnectionInfo ci : cons.values()) { + int weight = ci.nrofConnections; + write(ci.h1 + "--" + ci.h2 + " [weight=" + weight + "];"); + } + + // mention all hosts in the graph at least once + if (this.allHosts != null) { + for (DTNHost h : allHosts) { + write(h+ ";"); + } + } + + setPrefix(""); // don't indent anymore + write("}"); + + super.done(); + } + + /** + * Private class stores information of the connected hosts + * and nrof times they have connected. + */ + private class ConnectionInfo { + private DTNHost h1; + private DTNHost h2; + private int nrofConnections; + + public ConnectionInfo(DTNHost h1, DTNHost h2) { + this.h1 = h1; + this.h2 = h2; + this.nrofConnections = 1; + } + public boolean equals(Object o) { - if (o == null) return false; - return o.toString().equals(this.toString()); + if (o == null) return false; + return o.toString().equals(this.toString()); } - - public int hashCode() { - return toString().hashCode(); + + public int hashCode() { + return toString().hashCode(); } - - public String toString() { - return h1+HOST_DELIM+h2; + + public String toString() { + return h1+HOST_DELIM+h2; } - - public int compareTo(Object o) { - return nrofConnections - ((ConnectionInfo)o).nrofConnections; - } - } - -} + + public int compareTo(Object o) { + return nrofConnections - ((ConnectionInfo)o).nrofConnections; + } + } + +} diff --git a/report/BufferOccupancyReport.java b/report/BufferOccupancyReport.java index 1ce28d5ce..8171a6583 100644 --- a/report/BufferOccupancyReport.java +++ b/report/BufferOccupancyReport.java @@ -1,21 +1,21 @@ -/* +/* * Copyright 2010-2012 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package report; -/** +/** * Records the average buffer occupancy and its variance with format: *

* [Simulation time] [average buffer occupancy % [0..100] ] [variance] *

- * + * *

* The occupancy is calculated as an instantaneous snapshot every nth second * as defined by the occupancyInterval setting, not as an * average over time. *

- * + * * @author teemuk */ import java.util.List; @@ -28,42 +28,42 @@ public class BufferOccupancyReport extends Report implements UpdateListener { /** - * Record occupancy every nth second -setting id ({@value}). + * Record occupancy every nth second -setting id ({@value}). * Defines the interval how often (seconds) a new snapshot of buffer * occupancy is taken */ public static final String BUFFER_REPORT_INTERVAL = "occupancyInterval"; /** Default value for the snapshot interval */ public static final int DEFAULT_BUFFER_REPORT_INTERVAL = 5; - + private double lastRecord = Double.MIN_VALUE; private int interval; - + /** * Creates a new BufferOccupancyReport instance. */ public BufferOccupancyReport() { super(); - + Settings settings = getSettings(); if (settings.contains(BUFFER_REPORT_INTERVAL)) { interval = settings.getInt(BUFFER_REPORT_INTERVAL); } else { interval = -1; /* not found; use default */ } - + if (interval < 0) { /* not found or invalid value -> use default */ interval = DEFAULT_BUFFER_REPORT_INTERVAL; } } - + public void updated(List hosts) { if (SimClock.getTime() - lastRecord >= interval) { lastRecord = SimClock.getTime(); printLine(hosts); } } - + /** * Prints a snapshot of the average buffer occupancy * @param hosts The list of hosts in the simulation @@ -78,10 +78,10 @@ private void printLine(List hosts) { bufferOccupancy += tmp; bo2 += (tmp*tmp)/100.0; } - + double E_X = bufferOccupancy / hosts.size(); double Var_X = bo2 / hosts.size() - (E_X*E_X)/100.0; - + String output = format(SimClock.getTime()) + " " + format(E_X) + " " + format(Var_X); write(output); diff --git a/report/ConnectivityDtnsim2Report.java b/report/ConnectivityDtnsim2Report.java index d1c429c27..cb23b4423 100644 --- a/report/ConnectivityDtnsim2Report.java +++ b/report/ConnectivityDtnsim2Report.java @@ -1,57 +1,57 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import core.ConnectionListener; import core.DTNHost; - -/** + +/** * Link connectivity report generator for DTNSim2 input. - * Connections that start during the warm up period are ignored. - */ -public class ConnectivityDtnsim2Report extends Report - implements ConnectionListener { - - /** - * Constructor. - */ - public ConnectivityDtnsim2Report() { - init(); - } - + * Connections that start during the warm up period are ignored. + */ +public class ConnectivityDtnsim2Report extends Report + implements ConnectionListener { + + /** + * Constructor. + */ + public ConnectivityDtnsim2Report() { + init(); + } + public void hostsConnected(DTNHost h1, DTNHost h2) { if (isWarmup()) { addWarmupID(connectionString(h1, h2)); return; } - - newEvent(); - write(createTimeStamp() + " " + connectionString(h1, h2) + " up"); - } - + + newEvent(); + write(createTimeStamp() + " " + connectionString(h1, h2) + " up"); + } + public void hostsDisconnected(DTNHost h1, DTNHost h2) { String conString = connectionString(h1, h2); - + if (isWarmup() || isWarmupID(conString)) { removeWarmupID(conString); return; - } - - newEvent(); - write(createTimeStamp() + " " + conString + " down"); - } - - /** - * Creates and returns a "@" prefixed time stamp of the current simulation - * time - * @return time stamp of the current simulation time - */ - private String createTimeStamp() { - return String.format("@%.2f", getSimTime()); + } + + newEvent(); + write(createTimeStamp() + " " + conString + " down"); } - + + /** + * Creates and returns a "@" prefixed time stamp of the current simulation + * time + * @return time stamp of the current simulation time + */ + private String createTimeStamp() { + return String.format("@%.2f", getSimTime()); + } + /** * Creates and returns a String presentation of the connection where the * node with the lower network address is first @@ -66,6 +66,6 @@ private String connectionString(DTNHost h1, DTNHost h2) { else { return h2 + " <-> " + h1; } - } - -} + } + +} diff --git a/report/ConnectivityONEReport.java b/report/ConnectivityONEReport.java index 899c6e91a..5184fd5bb 100644 --- a/report/ConnectivityONEReport.java +++ b/report/ConnectivityONEReport.java @@ -1,55 +1,55 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import core.ConnectionListener; import core.DTNHost; - -/** + +/** * Link connectivity report generator for ONE StandardEventsReader input. - * Connections that start during the warm up period are ignored. - */ -public class ConnectivityONEReport extends Report - implements ConnectionListener { - - /** - * Constructor. - */ - public ConnectivityONEReport() { - init(); - } - + * Connections that start during the warm up period are ignored. + */ +public class ConnectivityONEReport extends Report + implements ConnectionListener { + + /** + * Constructor. + */ + public ConnectivityONEReport() { + init(); + } + public void hostsConnected(DTNHost h1, DTNHost h2) { if (isWarmup()) { addWarmupID(connectionString(h1, h2)); return; - } - newEvent(); - write(createTimeStamp() + " CONN " + connectionString(h1, h2) + " up"); - } - + } + newEvent(); + write(createTimeStamp() + " CONN " + connectionString(h1, h2) + " up"); + } + public void hostsDisconnected(DTNHost h1, DTNHost h2) { String conString = connectionString(h1, h2); - + if (isWarmup() || isWarmupID(conString)) { removeWarmupID(conString); return; - } - - write(createTimeStamp() + " CONN " + conString + " down"); - } - - /** - * Creates and returns a "@" prefixed time stamp of the current simulation - * time - * @return time stamp of the current simulation time - */ - private String createTimeStamp() { - return String.format("%.2f", getSimTime()); + } + + write(createTimeStamp() + " CONN " + conString + " down"); } - + + /** + * Creates and returns a "@" prefixed time stamp of the current simulation + * time + * @return time stamp of the current simulation time + */ + private String createTimeStamp() { + return String.format("%.2f", getSimTime()); + } + /** * Creates and returns a String presentation of the connection where the * node with the lower network address is first @@ -64,6 +64,6 @@ private String connectionString(DTNHost h1, DTNHost h2) { else { return h2.getAddress() + " " + h1.getAddress(); } - } - -} + } + +} diff --git a/report/ContactTimesReport.java b/report/ContactTimesReport.java index 8f1ca5178..9384ca429 100644 --- a/report/ContactTimesReport.java +++ b/report/ContactTimesReport.java @@ -1,213 +1,213 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import java.util.HashMap; import java.util.Vector; import core.ConnectionListener; import core.DTNHost; import core.Settings; - -/** - * Reports the node contact time (i.e., how long they were in the range + +/** + * Reports the node contact time (i.e., how long they were in the range * of each other) distribution. Report file contains the count of connections * that lasted for certain amount of time. Syntax:
- * time nrofContacts - */ -public class ContactTimesReport extends Report implements ConnectionListener { - protected HashMap connections; - private Vector nrofContacts; - - /** Granularity -setting id ({@value}). Defines how many simulated seconds - * are grouped in one reported interval. */ - public static final String GRANULARITY = "granularity"; - /** How many seconds are grouped in one group */ - protected double granularity; - - /** - * Constructor. - */ + * time nrofContacts + */ +public class ContactTimesReport extends Report implements ConnectionListener { + protected HashMap connections; + private Vector nrofContacts; + + /** Granularity -setting id ({@value}). Defines how many simulated seconds + * are grouped in one reported interval. */ + public static final String GRANULARITY = "granularity"; + /** How many seconds are grouped in one group */ + protected double granularity; + + /** + * Constructor. + */ public ContactTimesReport() { - Settings settings = getSettings(); - if (settings.contains(GRANULARITY)) { - this.granularity = settings.getDouble(GRANULARITY); - } - else { - this.granularity = 1.0; - } - - init(); - } - - @Override - protected void init() { - super.init(); - this.connections = new HashMap(); - this.nrofContacts = new Vector(); - } - + Settings settings = getSettings(); + if (settings.contains(GRANULARITY)) { + this.granularity = settings.getDouble(GRANULARITY); + } + else { + this.granularity = 1.0; + } + + init(); + } + + @Override + protected void init() { + super.init(); + this.connections = new HashMap(); + this.nrofContacts = new Vector(); + } + public void hostsConnected(DTNHost host1, DTNHost host2) { if (isWarmup()) { return; - } - addConnection(host1, host2); - } - - public void hostsDisconnected(DTNHost host1, DTNHost host2) { - newEvent(); - ConnectionInfo ci = removeConnection(host1, host2); - + } + addConnection(host1, host2); + } + + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + newEvent(); + ConnectionInfo ci = removeConnection(host1, host2); + if (ci == null) { return; /* the connection was started during the warm up period */ } - - ci.connectionEnd(); - increaseTimeCount(ci.getConnectionTime()); - } - - protected void addConnection(DTNHost host1, DTNHost host2) { - ConnectionInfo ci = new ConnectionInfo(host1, host2); - - assert !connections.containsKey(ci) : "Already contained "+ - " a connection of " + host1 + " and " + host2; - - connections.put(ci,ci); - } - - protected ConnectionInfo removeConnection(DTNHost host1, DTNHost host2) { - ConnectionInfo ci = new ConnectionInfo(host1, host2); - ci = connections.remove(ci); - return ci; - } - - /** - * Increases the amount of times a certain time value has been seen. - * @param time The time value that was seen - */ - protected void increaseTimeCount(double time) { - int index = (int)(time/this.granularity); - - if (index >= this.nrofContacts.size()) { - /* if biggest index so far, fill array with nulls up to - index+2 to keep the last time count always zero */ - this.nrofContacts.setSize(index + 2); - } - - Integer curValue = this.nrofContacts.get(index); - if (curValue == null) { // no value found -> put the first - this.nrofContacts.set(index, 1); - } - else { // value found -> increase the number by one - this.nrofContacts.set(index, curValue+1); - } - } - - @Override - public void done() { - - for (int i=0, n=this.nrofContacts.size(); i" + this.h2 + " [" + this.startTime - +"-"+ (this.endTime >0 ? this.endTime : "n/a") + "]"; - } - } -} + + ci.connectionEnd(); + increaseTimeCount(ci.getConnectionTime()); + } + + protected void addConnection(DTNHost host1, DTNHost host2) { + ConnectionInfo ci = new ConnectionInfo(host1, host2); + + assert !connections.containsKey(ci) : "Already contained "+ + " a connection of " + host1 + " and " + host2; + + connections.put(ci,ci); + } + + protected ConnectionInfo removeConnection(DTNHost host1, DTNHost host2) { + ConnectionInfo ci = new ConnectionInfo(host1, host2); + ci = connections.remove(ci); + return ci; + } + + /** + * Increases the amount of times a certain time value has been seen. + * @param time The time value that was seen + */ + protected void increaseTimeCount(double time) { + int index = (int)(time/this.granularity); + + if (index >= this.nrofContacts.size()) { + /* if biggest index so far, fill array with nulls up to + index+2 to keep the last time count always zero */ + this.nrofContacts.setSize(index + 2); + } + + Integer curValue = this.nrofContacts.get(index); + if (curValue == null) { // no value found -> put the first + this.nrofContacts.set(index, 1); + } + else { // value found -> increase the number by one + this.nrofContacts.set(index, curValue+1); + } + } + + @Override + public void done() { + + for (int i=0, n=this.nrofContacts.size(); i" + this.h2 + " [" + this.startTime + +"-"+ (this.endTime >0 ? this.endTime : "n/a") + "]"; + } + } +} diff --git a/report/ContactsDuringAnICTReport.java b/report/ContactsDuringAnICTReport.java index d6b291c6b..6c3485dc3 100644 --- a/report/ContactsDuringAnICTReport.java +++ b/report/ContactsDuringAnICTReport.java @@ -1,115 +1,115 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package report; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import core.ConnectionListener; -import core.DTNHost; -import core.UpdateListener; - -/** - * The number of contacts during an inter-contact time metric is similar to - * the inter-contact times metric, except that instead of measuring the time - * until a node meets again, we count the number of other nodes both of the - * nodes meet separately. In contrast to the inter-contact times, the number - * of contacts during an inter-contact is not symmetric, i.e. during an - * inter-contact both nodes wait the exact same time but will meet a different - * number of nodes. - * - * @author Frans Ekman - */ -public class ContactsDuringAnICTReport extends Report - implements ConnectionListener, UpdateListener { - - private boolean[][] areDisconnected; - private int[][] contactCount; - private LinkedList contactsDuringIC; - - private boolean updateHasBeenCalled; - - public ContactsDuringAnICTReport() { - super(); - init(); - } - - - @Override - protected void init() { - super.init(); - contactsDuringIC = new LinkedList(); - } - - - public void hostsConnected(DTNHost host1, DTNHost host2) { - if (!updateHasBeenCalled) { - return; - } - int id1 = host1.getAddress(); - int id2 = host2.getAddress(); - if (areDisconnected[id1][id2]) { - areDisconnected[id1][id2] = false; - areDisconnected[id2][id1] = false; - contactsDuringIC.add(new Integer(contactCount[id1][id2])); - contactsDuringIC.add(new Integer(contactCount[id2][id1])); - contactCount[id1][id2] = 0; - contactCount[id2][id1] = 0; - } - - incContactForAllDisconnectedNodes(host1); - incContactForAllDisconnectedNodes(host2); - - } - - private void incContactForAllDisconnectedNodes(DTNHost host) { - int id = host.getAddress(); - for (int i=0; i hosts) { - if (areDisconnected == null || contactCount == null) { - areDisconnected = new boolean[hosts.size()][hosts.size()]; - contactCount = new int[hosts.size()][hosts.size()]; - } - updateHasBeenCalled = true; - } - - @Override - public void done() { - Integer[] contacts = (Integer[])contactsDuringIC.toArray(new Integer[0]); - Arrays.sort(contacts); - - int count = 0; - int last = 0; - for (int i=0; i contactsDuringIC; + + private boolean updateHasBeenCalled; + + public ContactsDuringAnICTReport() { + super(); + init(); + } + + + @Override + protected void init() { + super.init(); + contactsDuringIC = new LinkedList(); + } + + + public void hostsConnected(DTNHost host1, DTNHost host2) { + if (!updateHasBeenCalled) { + return; + } + int id1 = host1.getAddress(); + int id2 = host2.getAddress(); + if (areDisconnected[id1][id2]) { + areDisconnected[id1][id2] = false; + areDisconnected[id2][id1] = false; + contactsDuringIC.add(new Integer(contactCount[id1][id2])); + contactsDuringIC.add(new Integer(contactCount[id2][id1])); + contactCount[id1][id2] = 0; + contactCount[id2][id1] = 0; + } + + incContactForAllDisconnectedNodes(host1); + incContactForAllDisconnectedNodes(host2); + + } + + private void incContactForAllDisconnectedNodes(DTNHost host) { + int id = host.getAddress(); + for (int i=0; i hosts) { + if (areDisconnected == null || contactCount == null) { + areDisconnected = new boolean[hosts.size()][hosts.size()]; + contactCount = new int[hosts.size()][hosts.size()]; + } + updateHasBeenCalled = true; + } + + @Override + public void done() { + Integer[] contacts = (Integer[])contactsDuringIC.toArray(new Integer[0]); + Arrays.sort(contacts); + + int count = 0; + int last = 0; + for (int i=0; i contactCounts; - private int currentHourCount; - private int currentHour; - - public ContactsPerHourReport() { - init(); - } - - @Override - public void init() { - super.init(); - contactCounts = new LinkedList(); - } - - public void hostsConnected(DTNHost host1, DTNHost host2) { - int time = SimClock.getIntTime() / 3600; - while (Math.floor(time) > currentHour) { - contactCounts.add(new Integer(currentHourCount)); - currentHourCount = 0; - currentHour++; - } - - currentHourCount++; - } - - public void hostsDisconnected(DTNHost host1, DTNHost host2) { - // Do nothing - } - - public void done() { - Iterator iterator = contactCounts.iterator(); - int hour = 0; - while (iterator.hasNext()) { - Integer count = (Integer)iterator.next(); - write(hour + "\t" + count); - hour++; - } - super.done(); - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.Iterator; +import java.util.LinkedList; + +import core.ConnectionListener; +import core.DTNHost; +import core.SimClock; + +/** + * This report counts the number of contacts each hour + * + * @author Frans Ekman + */ +public class ContactsPerHourReport extends Report implements ConnectionListener { + + private LinkedList contactCounts; + private int currentHourCount; + private int currentHour; + + public ContactsPerHourReport() { + init(); + } + + @Override + public void init() { + super.init(); + contactCounts = new LinkedList(); + } + + public void hostsConnected(DTNHost host1, DTNHost host2) { + int time = SimClock.getIntTime() / 3600; + while (Math.floor(time) > currentHour) { + contactCounts.add(new Integer(currentHourCount)); + currentHourCount = 0; + currentHour++; + } + + currentHourCount++; + } + + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + // Do nothing + } + + public void done() { + Iterator iterator = contactCounts.iterator(); + int hour = 0; + while (iterator.hasNext()) { + Integer count = (Integer)iterator.next(); + write(hour + "\t" + count); + hour++; + } + super.done(); + } + +} diff --git a/report/CreatedMessagesReport.java b/report/CreatedMessagesReport.java index 6630e61f0..00099758d 100644 --- a/report/CreatedMessagesReport.java +++ b/report/CreatedMessagesReport.java @@ -1,56 +1,56 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - -import core.DTNHost; -import core.Message; -import core.MessageListener; - -/** +package report; + +import core.DTNHost; +import core.Message; +import core.MessageListener; + +/** * Reports information about all created messages. Messages created during - * the warm up period are ignored. - * For output syntax, see {@link #HEADER}. - */ -public class CreatedMessagesReport extends Report implements MessageListener { - public static String HEADER = "# time ID size fromHost toHost TTL " + - "isResponse"; - - /** - * Constructor. - */ - public CreatedMessagesReport() { - init(); - } - - @Override - public void init() { - super.init(); - write(HEADER); - } + * the warm up period are ignored. + * For output syntax, see {@link #HEADER}. + */ +public class CreatedMessagesReport extends Report implements MessageListener { + public static String HEADER = "# time ID size fromHost toHost TTL " + + "isResponse"; + + /** + * Constructor. + */ + public CreatedMessagesReport() { + init(); + } + + @Override + public void init() { + super.init(); + write(HEADER); + } public void newMessage(Message m) { if (isWarmup()) { return; } - + int ttl = m.getTtl(); - write(format(getSimTime()) + " " + m.getId() + " " + + write(format(getSimTime()) + " " + m.getId() + " " + m.getSize() + " " + m.getFrom() + " " + m.getTo() + " " + - (ttl != Integer.MAX_VALUE ? ttl : "n/a") + + (ttl != Integer.MAX_VALUE ? ttl : "n/a") + (m.isResponse() ? " Y " : " N ")); } - + // nothing to implement for the rest - public void messageTransferred(Message m, DTNHost f, DTNHost t,boolean b) {} - public void messageDeleted(Message m, DTNHost where, boolean dropped) {} - public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + public void messageTransferred(Message m, DTNHost f, DTNHost t,boolean b) {} + public void messageDeleted(Message m, DTNHost where, boolean dropped) {} + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} - - @Override - public void done() { - super.done(); - } -} + + @Override + public void done() { + super.done(); + } +} diff --git a/report/DTN2Reporter.java b/report/DTN2Reporter.java index 887c45d94..82232b432 100644 --- a/report/DTN2Reporter.java +++ b/report/DTN2Reporter.java @@ -1,8 +1,8 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ - + package report; import core.DTN2Manager; @@ -25,22 +25,22 @@ public DTN2Reporter() { super.init(); DTN2Manager.setReporter(this); } - + // Implement MessageListener /** * Method is called when a new message is created * @param m Message that was created */ public void newMessage(Message m) {} - + /** * Method is called when a message's transfer is started * @param m The message that is going to be transferred - * @param from Node where the message is transferred from + * @param from Node where the message is transferred from * @param to Node where the message is transferred to */ public void messageTransferStarted(Message m, DTNHost from, DTNHost to){} - + /** * Method is called when a message is deleted * @param m The message that was deleted @@ -48,16 +48,16 @@ public void messageTransferStarted(Message m, DTNHost from, DTNHost to){} * @param dropped True if the message was dropped, false if removed */ public void messageDeleted(Message m, DTNHost where, boolean dropped){} - + /** - * Method is called when a message's transfer was aborted before + * Method is called when a message's transfer was aborted before * it finished * @param m The message that was being transferred - * @param from Node where the message was being transferred from + * @param from Node where the message was being transferred from * @param to Node where the message was being transferred to */ public void messageTransferAborted(Message m, DTNHost from, DTNHost to){} - + /** * Method is called when a message is successfully transferred from * a node to another. diff --git a/report/DeliveredMessagesReport.java b/report/DeliveredMessagesReport.java index d79c68e02..c62999eb4 100644 --- a/report/DeliveredMessagesReport.java +++ b/report/DeliveredMessagesReport.java @@ -1,38 +1,38 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import java.util.List; -import core.DTNHost; -import core.Message; -import core.MessageListener; - -/** +import core.DTNHost; +import core.Message; +import core.MessageListener; + +/** * Report information about all delivered messages. Messages created during - * the warm up period are ignored. - * For output syntax, see {@link #HEADER}. - */ -public class DeliveredMessagesReport extends Report implements MessageListener { + * the warm up period are ignored. + * For output syntax, see {@link #HEADER}. + */ +public class DeliveredMessagesReport extends Report implements MessageListener { public static String HEADER = "# time ID size hopcount deliveryTime " + - "fromHost toHost remainingTtl isResponse path"; - - /** - * Constructor. - */ - public DeliveredMessagesReport() { - init(); - } - - @Override - public void init() { - super.init(); - write(HEADER); - } + "fromHost toHost remainingTtl isResponse path"; + + /** + * Constructor. + */ + public DeliveredMessagesReport() { + init(); + } + + @Override + public void init() { + super.init(); + write(HEADER); + } - /** + /** * Returns the given messages hop path as a string * @param m The message * @return hop path as a string @@ -40,40 +40,40 @@ public void init() { private String getPathString(Message m) { List hops = m.getHops(); String str = m.getFrom().toString(); - + for (int i=1; i creationInfos; - - /** - * Constructor. - */ - public DistanceDelayReport() { - init(); - } - - @Override - protected void init() { - super.init(); - this.creationInfos = new HashMap(); - printHeader(); - } - - /** - * This is called when a message is transferred between nodes - */ - public void messageTransferred(Message m, DTNHost from, DTNHost to, - boolean firstDelivery) { - if (isWarmupID(m.getId()) || !firstDelivery) { - return; // report is only interested of first deliveries - } - + * Only messages created after the warm up period are counted. + * If message is not delivered, its delivery time & hop count are reported as -1 + */ +public class DistanceDelayReport extends Report implements MessageListener { + /** Syntax of the report lines */ + public static final String SYNTAX = + "distance at msg send, delivery time, hop count, MSG_ID"; + private HashMap creationInfos; + + /** + * Constructor. + */ + public DistanceDelayReport() { + init(); + } + + @Override + protected void init() { + super.init(); + this.creationInfos = new HashMap(); + printHeader(); + } + + /** + * This is called when a message is transferred between nodes + */ + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + if (isWarmupID(m.getId()) || !firstDelivery) { + return; // report is only interested of first deliveries + } + InfoTuple info = this.creationInfos.remove(m.getId()); if (info == null) { return; /* message was created before the warm up period */ } - - report(m.getId(), info.getLoc1().distance(info.getLoc2()), - getSimTime() - info.getTime(), m.getHops().size()-1); - } - - /** - * This is called when a new message is created - */ + + report(m.getId(), info.getLoc1().distance(info.getLoc2()), + getSimTime() - info.getTime(), m.getHops().size()-1); + } + + /** + * This is called when a new message is created + */ public void newMessage(Message m) { if (isWarmup()) { addWarmupID(m.getId()); return; } - - this.creationInfos.put( m.getId(), - new InfoTuple(getSimTime(), - m.getFrom().getLocation().clone(), - m.getTo().getLocation().clone()) ); - } - - /** - * Writes an informative header in the beginning of the file - */ - private void printHeader() { - write("# Scenario " + getScenarioName()); - write("# " + SYNTAX); - } - - /** - * Writes a report line - * @param id Id of the message - * @param startDistance Distance of the nodes when the message was creted - * @param time Time it took for the message to be delivered - * @param hopCount The amount of hops it took to deliver the message - */ - private void report(String id, double startDistance, double time, - int hopCount) { - write(format(startDistance) + " " + format(time) + " " + hopCount + - " " + id); - } - - /* nothing to implement for the rest */ - public void messageDeleted(Message m, DTNHost where, boolean dropped) {} - public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} - public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} - - public void done() { - // report rest of the messages as 'not delivered' (time == -1) - for (String id : creationInfos.keySet()) { - InfoTuple info = creationInfos.get(id); - report(id, info.getLoc1().distance(info.getLoc2()), -1, -1); - } - - super.done(); - } - - /** - * Private class that encapsulates time and location related information - */ - private class InfoTuple { - private double time; - private Coord loc1; - private Coord loc2; - - public InfoTuple(double time, Coord loc1, Coord loc2) { - this.time = time; - this.loc1 = loc1; - this.loc2 = loc2; - } - - public Coord getLoc1() { - return loc1; - } - - public Coord getLoc2() { - return loc2; - } - - public double getTime() { - return time; - } - } - -} + + this.creationInfos.put( m.getId(), + new InfoTuple(getSimTime(), + m.getFrom().getLocation().clone(), + m.getTo().getLocation().clone()) ); + } + + /** + * Writes an informative header in the beginning of the file + */ + private void printHeader() { + write("# Scenario " + getScenarioName()); + write("# " + SYNTAX); + } + + /** + * Writes a report line + * @param id Id of the message + * @param startDistance Distance of the nodes when the message was creted + * @param time Time it took for the message to be delivered + * @param hopCount The amount of hops it took to deliver the message + */ + private void report(String id, double startDistance, double time, + int hopCount) { + write(format(startDistance) + " " + format(time) + " " + hopCount + + " " + id); + } + + /* nothing to implement for the rest */ + public void messageDeleted(Message m, DTNHost where, boolean dropped) {} + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + + public void done() { + // report rest of the messages as 'not delivered' (time == -1) + for (String id : creationInfos.keySet()) { + InfoTuple info = creationInfos.get(id); + report(id, info.getLoc1().distance(info.getLoc2()), -1, -1); + } + + super.done(); + } + + /** + * Private class that encapsulates time and location related information + */ + private class InfoTuple { + private double time; + private Coord loc1; + private Coord loc2; + + public InfoTuple(double time, Coord loc1, Coord loc2) { + this.time = time; + this.loc1 = loc1; + this.loc2 = loc2; + } + + public Coord getLoc1() { + return loc1; + } + + public Coord getLoc2() { + return loc2; + } + + public double getTime() { + return time; + } + } + +} diff --git a/report/EncountersVSUniqueEncountersReport.java b/report/EncountersVSUniqueEncountersReport.java index 45522ebe7..72b960dcb 100644 --- a/report/EncountersVSUniqueEncountersReport.java +++ b/report/EncountersVSUniqueEncountersReport.java @@ -1,66 +1,66 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package report; - -import java.util.List; - -import core.ConnectionListener; -import core.DTNHost; -import core.UpdateListener; - -/** - * The total- vs. the unique encounters for each node - * - * @author Frans Ekman - */ -public class EncountersVSUniqueEncountersReport extends Report - implements ConnectionListener, UpdateListener { - - private TotalEncountersReport totalEncountersReport; - private UniqueEncountersReport uniqueEncountersReport; - - public EncountersVSUniqueEncountersReport() { - totalEncountersReport = new TotalEncountersReport(); - uniqueEncountersReport = new UniqueEncountersReport(); - } - - public void hostsConnected(DTNHost host1, DTNHost host2) { - totalEncountersReport.hostsConnected(host1, host2); - uniqueEncountersReport.hostsConnected(host1, host2); - } - - public void hostsDisconnected(DTNHost host1, DTNHost host2) { - totalEncountersReport.hostsDisconnected(host1, host2); - uniqueEncountersReport.hostsDisconnected(host1, host2); - } - - public void updated(List hosts) { - totalEncountersReport.updated(hosts); - uniqueEncountersReport.updated(hosts); - } - - @Override - public void done() { - int[] totalEncounters = totalEncountersReport.getEncounters(); - int[][] nodeRelationships = uniqueEncountersReport.getNodeRelationships(); - - for (int i=0; i 0) { - count++; - } - } - row += count; - write(row); - } - - super.done(); - } -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.List; + +import core.ConnectionListener; +import core.DTNHost; +import core.UpdateListener; + +/** + * The total- vs. the unique encounters for each node + * + * @author Frans Ekman + */ +public class EncountersVSUniqueEncountersReport extends Report + implements ConnectionListener, UpdateListener { + + private TotalEncountersReport totalEncountersReport; + private UniqueEncountersReport uniqueEncountersReport; + + public EncountersVSUniqueEncountersReport() { + totalEncountersReport = new TotalEncountersReport(); + uniqueEncountersReport = new UniqueEncountersReport(); + } + + public void hostsConnected(DTNHost host1, DTNHost host2) { + totalEncountersReport.hostsConnected(host1, host2); + uniqueEncountersReport.hostsConnected(host1, host2); + } + + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + totalEncountersReport.hostsDisconnected(host1, host2); + uniqueEncountersReport.hostsDisconnected(host1, host2); + } + + public void updated(List hosts) { + totalEncountersReport.updated(hosts); + uniqueEncountersReport.updated(hosts); + } + + @Override + public void done() { + int[] totalEncounters = totalEncountersReport.getEncounters(); + int[][] nodeRelationships = uniqueEncountersReport.getNodeRelationships(); + + for (int i=0; i 0) { + count++; + } + } + row += count; + write(row); + } + + super.done(); + } +} diff --git a/report/EnergyLevelReport.java b/report/EnergyLevelReport.java index b8b05fa26..9c5a81e40 100644 --- a/report/EnergyLevelReport.java +++ b/report/EnergyLevelReport.java @@ -1,96 +1,96 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package report; - -import java.util.HashSet; -import java.util.List; - -import core.DTNHost; -import core.Settings; -import core.SimError; -import core.UpdateListener; - -/** - * Node energy level report. Reports the energy level of all (or only some) - * nodes every configurable-amount-of seconds. Writes reports only after - * the warmup period. - */ -public class EnergyLevelReport extends Report implements UpdateListener { - /** Reporting granularity -setting id ({@value}). - * Defines the interval how often (seconds) a new snapshot of energy levels - * is created */ - public static final String GRANULARITY = "granularity"; - /** Optional reported nodes (comma separated list of network addresses). - * By default all nodes are reported. */ - public static final String REPORTED_NODES = "nodes"; - /** value of the granularity setting */ - protected final int granularity; - /** time of last update*/ - protected double lastUpdate; - /** Networks addresses (integers) of the nodes which are reported */ - protected HashSet reportedNodes; - - /** - * Constructor. Reads the settings and initializes the report module. - */ - public EnergyLevelReport() { - Settings settings = getSettings(); - this.lastUpdate = 0; - this.granularity = settings.getInt(GRANULARITY); - - if (settings.contains(REPORTED_NODES)) { - this.reportedNodes = new HashSet(); - for (Integer nodeId : settings.getCsvInts(REPORTED_NODES)) { - this.reportedNodes.add(nodeId); - } - } - else { - this.reportedNodes = null; - } - - init(); - } - - /** - * Creates a new snapshot of the energy levels if "granularity" - * seconds have passed since the last snapshot. - * @param hosts All the hosts in the world - */ - public void updated(List hosts) { - double simTime = getSimTime(); - if (isWarmup()) { - return; /* warmup period is on */ - } - /* creates a snapshot once every granularity seconds */ - if (simTime - lastUpdate >= granularity) { - createSnapshot(hosts); - this.lastUpdate = simTime - simTime % granularity; - } - } - - /** - * Creates a snapshot of energy levels - * @param hosts The list of hosts in the world - */ - private void createSnapshot(List hosts) { - write ("[" + (int)getSimTime() + "]"); /* simulation time stamp */ - for (DTNHost h : hosts) { - if (this.reportedNodes != null && - !this.reportedNodes.contains(h.getAddress())) { - continue; /* node not in the list */ - } - Double value = (Double)h.getComBus(). - getProperty(routing.util.EnergyModel.ENERGY_VALUE_ID); - if (value == null) { - throw new SimError("Host " + h + - " is not using energy model"); - } - - write(h.toString() + " " + format(value)); - } - - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.HashSet; +import java.util.List; + +import core.DTNHost; +import core.Settings; +import core.SimError; +import core.UpdateListener; + +/** + * Node energy level report. Reports the energy level of all (or only some) + * nodes every configurable-amount-of seconds. Writes reports only after + * the warmup period. + */ +public class EnergyLevelReport extends Report implements UpdateListener { + /** Reporting granularity -setting id ({@value}). + * Defines the interval how often (seconds) a new snapshot of energy levels + * is created */ + public static final String GRANULARITY = "granularity"; + /** Optional reported nodes (comma separated list of network addresses). + * By default all nodes are reported. */ + public static final String REPORTED_NODES = "nodes"; + /** value of the granularity setting */ + protected final int granularity; + /** time of last update*/ + protected double lastUpdate; + /** Networks addresses (integers) of the nodes which are reported */ + protected HashSet reportedNodes; + + /** + * Constructor. Reads the settings and initializes the report module. + */ + public EnergyLevelReport() { + Settings settings = getSettings(); + this.lastUpdate = 0; + this.granularity = settings.getInt(GRANULARITY); + + if (settings.contains(REPORTED_NODES)) { + this.reportedNodes = new HashSet(); + for (Integer nodeId : settings.getCsvInts(REPORTED_NODES)) { + this.reportedNodes.add(nodeId); + } + } + else { + this.reportedNodes = null; + } + + init(); + } + + /** + * Creates a new snapshot of the energy levels if "granularity" + * seconds have passed since the last snapshot. + * @param hosts All the hosts in the world + */ + public void updated(List hosts) { + double simTime = getSimTime(); + if (isWarmup()) { + return; /* warmup period is on */ + } + /* creates a snapshot once every granularity seconds */ + if (simTime - lastUpdate >= granularity) { + createSnapshot(hosts); + this.lastUpdate = simTime - simTime % granularity; + } + } + + /** + * Creates a snapshot of energy levels + * @param hosts The list of hosts in the world + */ + private void createSnapshot(List hosts) { + write ("[" + (int)getSimTime() + "]"); /* simulation time stamp */ + for (DTNHost h : hosts) { + if (this.reportedNodes != null && + !this.reportedNodes.contains(h.getAddress())) { + continue; /* node not in the list */ + } + Double value = (Double)h.getComBus(). + getProperty(routing.util.EnergyModel.ENERGY_VALUE_ID); + if (value == null) { + throw new SimError("Host " + h + + " is not using energy model"); + } + + write(h.toString() + " " + format(value)); + } + + } + +} diff --git a/report/EventLogReport.java b/report/EventLogReport.java index 1fb6d7184..adad1fe74 100644 --- a/report/EventLogReport.java +++ b/report/EventLogReport.java @@ -1,88 +1,88 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package report; - -import core.ConnectionListener; -import core.DTNHost; -import core.Message; -import core.MessageListener; -import input.StandardEventsReader; - -/** - * Report that creates same output as the GUI's event log panel but formatted - * like {@link input.StandardEventsReader} input. Message relying event has - * extra one-letter identifier to tell whether that message was delivered to - * final destination, delivered there again, or just normally relayed - * (see the public constants). - */ -public class EventLogReport extends Report - implements ConnectionListener, MessageListener { - - /** Extra info for message relayed event ("relayed"): {@value} */ - public static final String MESSAGE_TRANS_RELAYED = "R"; - /** Extra info for message relayed event ("delivered"): {@value} */ - public static final String MESSAGE_TRANS_DELIVERED = "D"; - /** Extra info for message relayed event ("delivered again"): {@value} */ - public static final String MESSAGE_TRANS_DELIVERED_AGAIN = "A"; - - /** - * Processes a log event by writing a line to the report file - * @param action The action as a string - * @param host1 First host involved in the event (if any, or null) - * @param host2 Second host involved in the event (if any, or null) - * @param message The message involved in the event (if any, or null) - * @param extra Extra info to append in the end of line (if any, or null) - */ - private void processEvent(final String action, final DTNHost host1, - final DTNHost host2, final Message message, final String extra) { - write(getSimTime() + " " + action + " " + (host1 != null ? host1 : "") - + (host2 != null ? (" " + host2) : "") - + (message != null ? " " + message : "") - + (extra != null ? " " + extra : "")); - } - - public void hostsConnected(DTNHost host1, DTNHost host2) { - processEvent(StandardEventsReader.CONNECTION, host1, host2, null, - StandardEventsReader.CONNECTION_UP); - } - - public void hostsDisconnected(DTNHost host1, DTNHost host2) { - processEvent(StandardEventsReader.CONNECTION, host1, host2, null, - StandardEventsReader.CONNECTION_DOWN); - } - - public void messageDeleted(Message m, DTNHost where, boolean dropped) { - processEvent((dropped ? StandardEventsReader.DROP : - StandardEventsReader.REMOVE), where, null, m, null); - } - - public void messageTransferred(Message m, DTNHost from, DTNHost to, - boolean firstDelivery) { - String extra; - if (firstDelivery) { - extra = MESSAGE_TRANS_DELIVERED; - } - else if (to == m.getTo()) { - extra = MESSAGE_TRANS_DELIVERED_AGAIN; - } - else { - extra = MESSAGE_TRANS_RELAYED; - } - - processEvent(StandardEventsReader.DELIVERED, from, to, m, extra); - } - - public void newMessage(Message m) { - processEvent(StandardEventsReader.CREATE, m.getFrom(), null, m, null); - } - - public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { - processEvent(StandardEventsReader.ABORT, from, to, m, null); - } - - public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { - processEvent(StandardEventsReader.SEND, from, to, m, null); - } -} \ No newline at end of file + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import core.ConnectionListener; +import core.DTNHost; +import core.Message; +import core.MessageListener; +import input.StandardEventsReader; + +/** + * Report that creates same output as the GUI's event log panel but formatted + * like {@link input.StandardEventsReader} input. Message relying event has + * extra one-letter identifier to tell whether that message was delivered to + * final destination, delivered there again, or just normally relayed + * (see the public constants). + */ +public class EventLogReport extends Report + implements ConnectionListener, MessageListener { + + /** Extra info for message relayed event ("relayed"): {@value} */ + public static final String MESSAGE_TRANS_RELAYED = "R"; + /** Extra info for message relayed event ("delivered"): {@value} */ + public static final String MESSAGE_TRANS_DELIVERED = "D"; + /** Extra info for message relayed event ("delivered again"): {@value} */ + public static final String MESSAGE_TRANS_DELIVERED_AGAIN = "A"; + + /** + * Processes a log event by writing a line to the report file + * @param action The action as a string + * @param host1 First host involved in the event (if any, or null) + * @param host2 Second host involved in the event (if any, or null) + * @param message The message involved in the event (if any, or null) + * @param extra Extra info to append in the end of line (if any, or null) + */ + private void processEvent(final String action, final DTNHost host1, + final DTNHost host2, final Message message, final String extra) { + write(getSimTime() + " " + action + " " + (host1 != null ? host1 : "") + + (host2 != null ? (" " + host2) : "") + + (message != null ? " " + message : "") + + (extra != null ? " " + extra : "")); + } + + public void hostsConnected(DTNHost host1, DTNHost host2) { + processEvent(StandardEventsReader.CONNECTION, host1, host2, null, + StandardEventsReader.CONNECTION_UP); + } + + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + processEvent(StandardEventsReader.CONNECTION, host1, host2, null, + StandardEventsReader.CONNECTION_DOWN); + } + + public void messageDeleted(Message m, DTNHost where, boolean dropped) { + processEvent((dropped ? StandardEventsReader.DROP : + StandardEventsReader.REMOVE), where, null, m, null); + } + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + String extra; + if (firstDelivery) { + extra = MESSAGE_TRANS_DELIVERED; + } + else if (to == m.getTo()) { + extra = MESSAGE_TRANS_DELIVERED_AGAIN; + } + else { + extra = MESSAGE_TRANS_RELAYED; + } + + processEvent(StandardEventsReader.DELIVERED, from, to, m, extra); + } + + public void newMessage(Message m) { + processEvent(StandardEventsReader.CREATE, m.getFrom(), null, m, null); + } + + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { + processEvent(StandardEventsReader.ABORT, from, to, m, null); + } + + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { + processEvent(StandardEventsReader.SEND, from, to, m, null); + } +} diff --git a/report/InterContactTimesReport.java b/report/InterContactTimesReport.java index 98ead3b36..9351c57c9 100644 --- a/report/InterContactTimesReport.java +++ b/report/InterContactTimesReport.java @@ -1,35 +1,35 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import core.DTNHost; - -/** + +/** * Reports the inter-contact time (i.e., the time between the end of previous * contact and the beginning of a new contact between two hosts) distribution. - * The syntax of the report file is the same as in {@link ContactTimesReport}. - */ -public class InterContactTimesReport extends ContactTimesReport { - - @Override - public void hostsConnected(DTNHost host1, DTNHost host2) { - ConnectionInfo ci = this.removeConnection(host1, host2); - - if (ci != null) { // connected again - newEvent(); - ci.connectionEnd(); - increaseTimeCount(ci.getConnectionTime()); - } - } - - @Override + * The syntax of the report file is the same as in {@link ContactTimesReport}. + */ +public class InterContactTimesReport extends ContactTimesReport { + + @Override + public void hostsConnected(DTNHost host1, DTNHost host2) { + ConnectionInfo ci = this.removeConnection(host1, host2); + + if (ci != null) { // connected again + newEvent(); + ci.connectionEnd(); + increaseTimeCount(ci.getConnectionTime()); + } + } + + @Override public void hostsDisconnected(DTNHost host1, DTNHost host2) { if (isWarmup()) { return; - } - // start counting time to next connection - this.addConnection(host1, host2); - } -} + } + // start counting time to next connection + this.addConnection(host1, host2); + } +} diff --git a/report/MessageAvailabilityReport.java b/report/MessageAvailabilityReport.java index 6715a5c48..52983de28 100644 --- a/report/MessageAvailabilityReport.java +++ b/report/MessageAvailabilityReport.java @@ -1,116 +1,116 @@ -/* - * Copyright 2011 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package report; - -import java.util.HashSet; -import java.util.List; -import java.util.Random; -import java.util.Set; - -import core.Connection; -import core.DTNHost; -import core.Message; -import core.Settings; -import core.SettingsError; - -/** - * Reports which messages are available (either in the buffer or at one - * of the connected hosts' buffer) for certain, randomly selected, - * tracked hosts. Supports the same settings as the - * {@link MessageLocationReport} - */ -public class MessageAvailabilityReport extends MessageLocationReport { - - /** Number of tracked hosts -setting id ({@value}). Defines how many - * hosts are selected for sampling message availability */ - public static final String NROF_HOSTS_S = "nrofHosts"; - - private int nrofHosts; - private Set trackedHosts; - private Random rng; - - public MessageAvailabilityReport() { - super(); - Settings s = getSettings(); - nrofHosts = s.getInt(NROF_HOSTS_S, -1); - this.rng = new Random(nrofHosts); - - this.trackedHosts = null; - } - - /** - * Randomly selects the hosts to track - * @param allHosts All hosts in the scenario - * @return The set of tracked hosts - */ - private Set selectTrackedHosts(List allHosts) { - Set trackedHosts = new HashSet(); - - if (this.nrofHosts > allHosts.size()) { - throw new SettingsError("Can't use more hosts than there are " + - "in the simulation scenario"); - } - - - for (int i=0; i hosts) { - write("[" + (int) getSimTime() + "]"); /* write sim time stamp */ - - if (this.trackedHosts == null) { - this.trackedHosts = selectTrackedHosts(hosts); - } - - for (DTNHost host : hosts) { - Set msgIds = null; - String idString = ""; - - if (! this.trackedHosts.contains(host)) { - continue; - } - - msgIds = new HashSet(); - - /* add own messages */ - for (Message m : host.getMessageCollection()) { - if (!isTracked(m)) { - continue; - } - msgIds.add(m.getId()); - } - /* add all peer messages */ - for (Connection c : host.getConnections()) { - DTNHost peer = c.getOtherNode(host); - for (Message m : peer.getMessageCollection()) { - if (!isTracked(m)) { - continue; - } - msgIds.add(m.getId()); - } - } - - for (String id : msgIds) { - idString += " " + id; - } - - write(host + idString); - } - } -} \ No newline at end of file +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; +import core.SettingsError; + +/** + * Reports which messages are available (either in the buffer or at one + * of the connected hosts' buffer) for certain, randomly selected, + * tracked hosts. Supports the same settings as the + * {@link MessageLocationReport} + */ +public class MessageAvailabilityReport extends MessageLocationReport { + + /** Number of tracked hosts -setting id ({@value}). Defines how many + * hosts are selected for sampling message availability */ + public static final String NROF_HOSTS_S = "nrofHosts"; + + private int nrofHosts; + private Set trackedHosts; + private Random rng; + + public MessageAvailabilityReport() { + super(); + Settings s = getSettings(); + nrofHosts = s.getInt(NROF_HOSTS_S, -1); + this.rng = new Random(nrofHosts); + + this.trackedHosts = null; + } + + /** + * Randomly selects the hosts to track + * @param allHosts All hosts in the scenario + * @return The set of tracked hosts + */ + private Set selectTrackedHosts(List allHosts) { + Set trackedHosts = new HashSet(); + + if (this.nrofHosts > allHosts.size()) { + throw new SettingsError("Can't use more hosts than there are " + + "in the simulation scenario"); + } + + + for (int i=0; i hosts) { + write("[" + (int) getSimTime() + "]"); /* write sim time stamp */ + + if (this.trackedHosts == null) { + this.trackedHosts = selectTrackedHosts(hosts); + } + + for (DTNHost host : hosts) { + Set msgIds = null; + String idString = ""; + + if (! this.trackedHosts.contains(host)) { + continue; + } + + msgIds = new HashSet(); + + /* add own messages */ + for (Message m : host.getMessageCollection()) { + if (!isTracked(m)) { + continue; + } + msgIds.add(m.getId()); + } + /* add all peer messages */ + for (Connection c : host.getConnections()) { + DTNHost peer = c.getOtherNode(host); + for (Message m : peer.getMessageCollection()) { + if (!isTracked(m)) { + continue; + } + msgIds.add(m.getId()); + } + } + + for (String id : msgIds) { + idString += " " + id; + } + + write(host + idString); + } + } +} diff --git a/report/MessageCopyCountReport.java b/report/MessageCopyCountReport.java index b5d8b081b..59454c2bf 100644 --- a/report/MessageCopyCountReport.java +++ b/report/MessageCopyCountReport.java @@ -1,52 +1,52 @@ -/* - * Copyright 2011 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package report; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import core.DTNHost; -import core.Message; - -/** - * Reports the amount of messages in the system at each time interval. Uses the - * same settings as the {@link MessageLocationReport} - */ -public class MessageCopyCountReport extends MessageLocationReport { - - /** - * Creates a snapshot of message counts - * @param hosts The list of hosts in the world - */ - @Override - protected void createSnapshot(List hosts) { - Map counts = new HashMap(); - write("[" + (int) getSimTime() + "]"); /* write sim time stamp */ - ArrayList keys; - - for (DTNHost host : hosts) { - for (Message m : host.getMessageCollection()) { - Integer oldCount; - if (!isTracked(m)) { - continue; - } - oldCount = counts.get(m.getId()); - counts.put(m.getId(), (oldCount == null ? 1 : oldCount + 1)); - } - } - - keys = new ArrayList(counts.keySet()); - Collections.sort(keys); - - for (String key : keys) { - write(key + " " + counts.get(key)); - } - - } - -} +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import core.DTNHost; +import core.Message; + +/** + * Reports the amount of messages in the system at each time interval. Uses the + * same settings as the {@link MessageLocationReport} + */ +public class MessageCopyCountReport extends MessageLocationReport { + + /** + * Creates a snapshot of message counts + * @param hosts The list of hosts in the world + */ + @Override + protected void createSnapshot(List hosts) { + Map counts = new HashMap(); + write("[" + (int) getSimTime() + "]"); /* write sim time stamp */ + ArrayList keys; + + for (DTNHost host : hosts) { + for (Message m : host.getMessageCollection()) { + Integer oldCount; + if (!isTracked(m)) { + continue; + } + oldCount = counts.get(m.getId()); + counts.put(m.getId(), (oldCount == null ? 1 : oldCount + 1)); + } + } + + keys = new ArrayList(counts.keySet()); + Collections.sort(keys); + + for (String key : keys) { + write(key + " " + counts.get(key)); + } + + } + +} diff --git a/report/MessageDelayReport.java b/report/MessageDelayReport.java index abb729872..531e9bbdd 100644 --- a/report/MessageDelayReport.java +++ b/report/MessageDelayReport.java @@ -1,81 +1,81 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import java.util.ArrayList; import java.util.List; import core.DTNHost; import core.Message; import core.MessageListener; - -/** - * Reports delivered messages' delays (one line per delivered message) + +/** + * Reports delivered messages' delays (one line per delivered message) * and cumulative delivery probability sorted by message delays. - * Ignores the messages that were created during the warm up period. - */ -public class MessageDelayReport extends Report implements MessageListener { - public static final String HEADER = - "# messageDelay cumulativeProbability"; - /** all message delays */ - private List delays; - private int nrofCreated; - - /** - * Constructor. - */ - public MessageDelayReport() { - init(); - } - - @Override - public void init() { - super.init(); - write(HEADER); - this.delays = new ArrayList(); - this.nrofCreated = 0; - } - + * Ignores the messages that were created during the warm up period. + */ +public class MessageDelayReport extends Report implements MessageListener { + public static final String HEADER = + "# messageDelay cumulativeProbability"; + /** all message delays */ + private List delays; + private int nrofCreated; + + /** + * Constructor. + */ + public MessageDelayReport() { + init(); + } + + @Override + public void init() { + super.init(); + write(HEADER); + this.delays = new ArrayList(); + this.nrofCreated = 0; + } + public void newMessage(Message m) { if (isWarmup()) { addWarmupID(m.getId()); } - else { + else { this.nrofCreated++; - } - } - - public void messageTransferred(Message m, DTNHost from, DTNHost to, - boolean firstDelivery) { - if (firstDelivery && !isWarmupID(m.getId())) { - this.delays.add(getSimTime() - m.getCreationTime()); - } - - } - - @Override - public void done() { - if (delays.size() == 0) { - write("# no messages delivered in sim time "+format(getSimTime())); - super.done(); - return; - } - double cumProb = 0; // cumulative probability - - java.util.Collections.sort(delays); - - for (int i=0; i < delays.size(); i++) { - cumProb += 1.0/nrofCreated; - write(format(delays.get(i)) + " " + format(cumProb)); - } - super.done(); - } - - // nothing to implement for the rest - public void messageDeleted(Message m, DTNHost where, boolean dropped) {} - public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + } + } + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + if (firstDelivery && !isWarmupID(m.getId())) { + this.delays.add(getSimTime() - m.getCreationTime()); + } + + } + + @Override + public void done() { + if (delays.size() == 0) { + write("# no messages delivered in sim time "+format(getSimTime())); + super.done(); + return; + } + double cumProb = 0; // cumulative probability + + java.util.Collections.sort(delays); + + for (int i=0; i < delays.size(); i++) { + cumProb += 1.0/nrofCreated; + write(format(delays.get(i)) + " " + format(cumProb)); + } + super.done(); + } + + // nothing to implement for the rest + public void messageDeleted(Message m, DTNHost where, boolean dropped) {} + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} - -} + +} diff --git a/report/MessageDeliveryReport.java b/report/MessageDeliveryReport.java index acafecf58..386c4173f 100644 --- a/report/MessageDeliveryReport.java +++ b/report/MessageDeliveryReport.java @@ -1,72 +1,72 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import core.DTNHost; import core.Message; import core.MessageListener; - -/** - * Report for of amount of messages delivered vs. time. A new report line + +/** + * Report for of amount of messages delivered vs. time. A new report line * is created every time when either a message is created or delivered. - * Messages created during the warm up period are ignored. - * For output syntax, see {@link #HEADER}. - */ -public class MessageDeliveryReport extends Report implements MessageListener { - public static String HEADER="# time created delivered delivered/created"; - private int created; - private int delivered; - - /** - * Constructor. - */ - public MessageDeliveryReport() { - init(); - } - - @Override - public void init() { - super.init(); - created = 0; - delivered = 0; - write(HEADER); - } - - public void messageTransferred(Message m, DTNHost from, DTNHost to, - boolean firstDelivery) { - if (firstDelivery && !isWarmup() && !isWarmupID(m.getId())) { - delivered++; - reportValues(); - } - } - + * Messages created during the warm up period are ignored. + * For output syntax, see {@link #HEADER}. + */ +public class MessageDeliveryReport extends Report implements MessageListener { + public static String HEADER="# time created delivered delivered/created"; + private int created; + private int delivered; + + /** + * Constructor. + */ + public MessageDeliveryReport() { + init(); + } + + @Override + public void init() { + super.init(); + created = 0; + delivered = 0; + write(HEADER); + } + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + if (firstDelivery && !isWarmup() && !isWarmupID(m.getId())) { + delivered++; + reportValues(); + } + } + public void newMessage(Message m) { if (isWarmup()) { addWarmupID(m.getId()); return; - } - created++; - reportValues(); - } - - /** - * Writes the current values to report file - */ - private void reportValues() { - double prob = (1.0 * delivered) / created; - write(format(getSimTime()) + " " + created + " " + delivered + - " " + format(prob)); - } - - // nothing to implement for the rest - public void messageDeleted(Message m, DTNHost where, boolean dropped) {} - public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + } + created++; + reportValues(); + } + + /** + * Writes the current values to report file + */ + private void reportValues() { + double prob = (1.0 * delivered) / created; + write(format(getSimTime()) + " " + created + " " + delivered + + " " + format(prob)); + } + + // nothing to implement for the rest + public void messageDeleted(Message m, DTNHost where, boolean dropped) {} + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} - @Override - public void done() { - super.done(); - } -} + @Override + public void done() { + super.done(); + } +} diff --git a/report/MessageGraphvizReport.java b/report/MessageGraphvizReport.java index 51066ad7b..bcd0210b5 100644 --- a/report/MessageGraphvizReport.java +++ b/report/MessageGraphvizReport.java @@ -1,79 +1,79 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import java.util.List; import java.util.Vector; import core.DTNHost; import core.Message; import core.MessageListener; - -/** + +/** * Creates a graphviz compatible graph of messages that were passed. - * Messages created during the warm up period are ignored. - */ -public class MessageGraphvizReport extends Report implements MessageListener { - /** Name of the graphviz report ({@value})*/ - public static final String GRAPH_NAME = "msggraph"; - private Vector deliveredMessages; - - /** - * Constructor. - */ - public MessageGraphvizReport() { - init(); - } - - protected void init() { - super.init(); - this.deliveredMessages = new Vector(); - } + * Messages created during the warm up period are ignored. + */ +public class MessageGraphvizReport extends Report implements MessageListener { + /** Name of the graphviz report ({@value})*/ + public static final String GRAPH_NAME = "msggraph"; + private Vector deliveredMessages; + + /** + * Constructor. + */ + public MessageGraphvizReport() { + init(); + } + + protected void init() { + super.init(); + this.deliveredMessages = new Vector(); + } public void newMessage(Message m) { if (isWarmup()) { addWarmupID(m.getId()); } } - - public void messageTransferred(Message m, DTNHost from, - DTNHost to, boolean firstDelivery) { - if (firstDelivery && !isWarmupID(m.getId())) { - newEvent(); - this.deliveredMessages.add(m); - } - } + + public void messageTransferred(Message m, DTNHost from, + DTNHost to, boolean firstDelivery) { + if (firstDelivery && !isWarmupID(m.getId())) { + newEvent(); + this.deliveredMessages.add(m); + } + } /* nothing to implement for these */ - public void messageDeleted(Message m, DTNHost where, boolean dropped) { } - public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + public void messageDeleted(Message m, DTNHost where, boolean dropped) { } + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} - - @Override - public void done() { - write("/* scenario " + getScenarioName() + "\n" + - deliveredMessages.size() + " messages delivered at " + - "sim time " + getSimTime() + " */") ; - write("digraph " + GRAPH_NAME + " {"); - setPrefix("\t"); // indent following lines by one tab - - for (Message m : deliveredMessages) { - List path = m.getHops(); - String pathString = path.remove(0).toString(); // start node - - for (DTNHost next : path) { - pathString += "->" + next.toString(); - } - - write (pathString + ";"); - } - - setPrefix(""); // don't indent anymore - write("}"); - - super.done(); - } - -} + + @Override + public void done() { + write("/* scenario " + getScenarioName() + "\n" + + deliveredMessages.size() + " messages delivered at " + + "sim time " + getSimTime() + " */") ; + write("digraph " + GRAPH_NAME + " {"); + setPrefix("\t"); // indent following lines by one tab + + for (Message m : deliveredMessages) { + List path = m.getHops(); + String pathString = path.remove(0).toString(); // start node + + for (DTNHost next : path) { + pathString += "->" + next.toString(); + } + + write (pathString + ";"); + } + + setPrefix(""); // don't indent anymore + write("}"); + + super.done(); + } + +} diff --git a/report/MessageLocationReport.java b/report/MessageLocationReport.java index d1d266586..1158db53d 100644 --- a/report/MessageLocationReport.java +++ b/report/MessageLocationReport.java @@ -1,108 +1,108 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package report; - -import java.util.HashSet; -import java.util.List; - -import core.DTNHost; -import core.Message; -import core.Settings; -import core.UpdateListener; - - -/** - * Message location report. Reports the location (coordinates) of messages. - * The messages that are reported and the reporting interval can be configured. - */ -public class MessageLocationReport extends Report implements UpdateListener { - /** Reporting granularity -setting id ({@value}). - * Defines the interval how often (seconds) a new snapshot of message - * locations is created */ - public static final String GRANULARITY = "granularity"; - /** Reported messages -setting id ({@value}). - * Defines the IDs of the messages that are reported - * (comma separated list). Unless defined, all messages are reported. */ - public static final String REPORTED_MESSAGES = "messages"; - /** value of the granularity setting */ - protected final int granularity; - /** time of last update*/ - protected double lastUpdate; - /** Identifiers of the message which are reported */ - protected HashSet reportedMessages; - - /** - * Constructor. Reads the settings and initializes the report module. - */ - public MessageLocationReport() { - Settings settings = getSettings(); - this.lastUpdate = 0; - this.granularity = settings.getInt(GRANULARITY); - - if (settings.contains(REPORTED_MESSAGES)) { - this.reportedMessages = new HashSet(); - for (String msgId : settings.getCsvSetting(REPORTED_MESSAGES)) { - this.reportedMessages.add(msgId); - } - } else { - this.reportedMessages = null; /* all messages */ - } - - init(); - } - - /** - * Creates a new snapshot of the message locations if "granularity" - * seconds have passed since the last snapshot. - * @param hosts All the hosts in the world - */ - public void updated(List hosts) { - double simTime = getSimTime(); - /* creates a snapshot once every granularity seconds */ - if (simTime - lastUpdate >= granularity) { - createSnapshot(hosts); - this.lastUpdate = simTime - simTime % granularity; - } - } - - /** - * Returns true if the given message is tracked by the report - * @param m The message - * @return True if the message is tracked, false if not - */ - protected boolean isTracked(Message m) { - return (this.reportedMessages == null || - this.reportedMessages.contains(m.getId())); - } - - /** - * Creates a snapshot of message locations - * @param hosts The list of hosts in the world - */ - protected void createSnapshot(List hosts) { - boolean isFirstMessage; - String reportLine; - - write ("[" + (int)getSimTime() + "]"); /* write sim time stamp */ - - for (DTNHost host : hosts) { - isFirstMessage = true; - reportLine = ""; - for (Message m : host.getMessageCollection()) { - if (isTracked(m)) { - if (isFirstMessage) { - reportLine = host.getLocation().toString(); - isFirstMessage = false; - } - reportLine += " " + m.getId(); - } - } - if (reportLine.length() > 0) { - write(reportLine); /* write coordinate and message IDs */ - } - } - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.HashSet; +import java.util.List; + +import core.DTNHost; +import core.Message; +import core.Settings; +import core.UpdateListener; + + +/** + * Message location report. Reports the location (coordinates) of messages. + * The messages that are reported and the reporting interval can be configured. + */ +public class MessageLocationReport extends Report implements UpdateListener { + /** Reporting granularity -setting id ({@value}). + * Defines the interval how often (seconds) a new snapshot of message + * locations is created */ + public static final String GRANULARITY = "granularity"; + /** Reported messages -setting id ({@value}). + * Defines the IDs of the messages that are reported + * (comma separated list). Unless defined, all messages are reported. */ + public static final String REPORTED_MESSAGES = "messages"; + /** value of the granularity setting */ + protected final int granularity; + /** time of last update*/ + protected double lastUpdate; + /** Identifiers of the message which are reported */ + protected HashSet reportedMessages; + + /** + * Constructor. Reads the settings and initializes the report module. + */ + public MessageLocationReport() { + Settings settings = getSettings(); + this.lastUpdate = 0; + this.granularity = settings.getInt(GRANULARITY); + + if (settings.contains(REPORTED_MESSAGES)) { + this.reportedMessages = new HashSet(); + for (String msgId : settings.getCsvSetting(REPORTED_MESSAGES)) { + this.reportedMessages.add(msgId); + } + } else { + this.reportedMessages = null; /* all messages */ + } + + init(); + } + + /** + * Creates a new snapshot of the message locations if "granularity" + * seconds have passed since the last snapshot. + * @param hosts All the hosts in the world + */ + public void updated(List hosts) { + double simTime = getSimTime(); + /* creates a snapshot once every granularity seconds */ + if (simTime - lastUpdate >= granularity) { + createSnapshot(hosts); + this.lastUpdate = simTime - simTime % granularity; + } + } + + /** + * Returns true if the given message is tracked by the report + * @param m The message + * @return True if the message is tracked, false if not + */ + protected boolean isTracked(Message m) { + return (this.reportedMessages == null || + this.reportedMessages.contains(m.getId())); + } + + /** + * Creates a snapshot of message locations + * @param hosts The list of hosts in the world + */ + protected void createSnapshot(List hosts) { + boolean isFirstMessage; + String reportLine; + + write ("[" + (int)getSimTime() + "]"); /* write sim time stamp */ + + for (DTNHost host : hosts) { + isFirstMessage = true; + reportLine = ""; + for (Message m : host.getMessageCollection()) { + if (isTracked(m)) { + if (isFirstMessage) { + reportLine = host.getLocation().toString(); + isFirstMessage = false; + } + reportLine += " " + m.getId(); + } + } + if (reportLine.length() > 0) { + write(reportLine); /* write coordinate and message IDs */ + } + } + } + +} diff --git a/report/MessageReport.java b/report/MessageReport.java index afb373c29..1a312b1b0 100644 --- a/report/MessageReport.java +++ b/report/MessageReport.java @@ -1,61 +1,61 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import core.DTNHost; import core.Message; import core.MessageListener; - -/** + +/** * Reports delivered messages - * report: - * message_id creation_time deliver_time (duplicate) - */ -public class MessageReport extends Report implements MessageListener { - public static final String HEADER = - "# messages: ID, start time, end time"; - /** all message delays */ - - /** - * Constructor. - */ - public MessageReport() { - init(); - } - - @Override - public void init() { - super.init(); - write(HEADER); - } - - public void newMessage(Message m) {} - - public void messageTransferred(Message m, DTNHost from, DTNHost to, + * report: + * message_id creation_time deliver_time (duplicate) + */ +public class MessageReport extends Report implements MessageListener { + public static final String HEADER = + "# messages: ID, start time, end time"; + /** all message delays */ + + /** + * Constructor. + */ + public MessageReport() { + init(); + } + + @Override + public void init() { + super.init(); + write(HEADER); + } + + public void newMessage(Message m) {} + + public void messageTransferred(Message m, DTNHost from, DTNHost to, boolean firstDelivery) { if (firstDelivery) { - write(m.getId() + " " - + format(m.getCreationTime()) + " " + write(m.getId() + " " + + format(m.getCreationTime()) + " " + format(getSimTime())); } else { if (to.getAddress() == m.getTo().getAddress()) { - write(m.getId() + " " - + format(m.getCreationTime()) + " " + write(m.getId() + " " + + format(m.getCreationTime()) + " " + format(getSimTime()) + " duplicate"); } - } - } - - @Override + } + } + + @Override public void done() { super.done(); - } - - // nothing to implement for the rest - public void messageDeleted(Message m, DTNHost where, boolean dropped) {} - public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + } + + // nothing to implement for the rest + public void messageDeleted(Message m, DTNHost where, boolean dropped) {} + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} - -} + +} diff --git a/report/MessageStatsReport.java b/report/MessageStatsReport.java index 33fe2d863..8d2a29b8c 100644 --- a/report/MessageStatsReport.java +++ b/report/MessageStatsReport.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -12,171 +12,171 @@ import core.DTNHost; import core.Message; import core.MessageListener; - -/** - * Report for generating different kind of total statistics about message + +/** + * Report for generating different kind of total statistics about message * relaying performance. Messages that were created during the warm up period - * are ignored. - *

Note: if some statistics could not be created (e.g. - * overhead ratio if no messages were delivered) "NaN" is reported for - * double values and zero for integer median(s). - */ -public class MessageStatsReport extends Report implements MessageListener { - private Map creationTimes; - private List latencies; - private List hopCounts; - private List msgBufferTime; - private List rtt; // round trip times - - private int nrofDropped; - private int nrofRemoved; - private int nrofStarted; - private int nrofAborted; - private int nrofRelayed; - private int nrofCreated; - private int nrofResponseReqCreated; - private int nrofResponseDelivered; + * are ignored. + *

Note: if some statistics could not be created (e.g. + * overhead ratio if no messages were delivered) "NaN" is reported for + * double values and zero for integer median(s). + */ +public class MessageStatsReport extends Report implements MessageListener { + private Map creationTimes; + private List latencies; + private List hopCounts; + private List msgBufferTime; + private List rtt; // round trip times + + private int nrofDropped; + private int nrofRemoved; + private int nrofStarted; + private int nrofAborted; + private int nrofRelayed; + private int nrofCreated; + private int nrofResponseReqCreated; + private int nrofResponseDelivered; private int nrofDelivered; - - /** - * Constructor. - */ - public MessageStatsReport() { - init(); - } - - @Override - protected void init() { - super.init(); - this.creationTimes = new HashMap(); - this.latencies = new ArrayList(); - this.msgBufferTime = new ArrayList(); - this.hopCounts = new ArrayList(); - this.rtt = new ArrayList(); - - this.nrofDropped = 0; - this.nrofRemoved = 0; - this.nrofStarted = 0; - this.nrofAborted = 0; - this.nrofRelayed = 0; - this.nrofCreated = 0; - this.nrofResponseReqCreated = 0; - this.nrofResponseDelivered = 0; - this.nrofDelivered = 0; - } - - + + /** + * Constructor. + */ + public MessageStatsReport() { + init(); + } + + @Override + protected void init() { + super.init(); + this.creationTimes = new HashMap(); + this.latencies = new ArrayList(); + this.msgBufferTime = new ArrayList(); + this.hopCounts = new ArrayList(); + this.rtt = new ArrayList(); + + this.nrofDropped = 0; + this.nrofRemoved = 0; + this.nrofStarted = 0; + this.nrofAborted = 0; + this.nrofRelayed = 0; + this.nrofCreated = 0; + this.nrofResponseReqCreated = 0; + this.nrofResponseDelivered = 0; + this.nrofDelivered = 0; + } + + public void messageDeleted(Message m, DTNHost where, boolean dropped) { if (isWarmupID(m.getId())) { return; } - - if (dropped) { - this.nrofDropped++; - } - else { - this.nrofRemoved++; - } - - this.msgBufferTime.add(getSimTime() - m.getReceiveTime()); - } - - + + if (dropped) { + this.nrofDropped++; + } + else { + this.nrofRemoved++; + } + + this.msgBufferTime.add(getSimTime() - m.getReceiveTime()); + } + + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { if (isWarmupID(m.getId())) { return; } - - this.nrofAborted++; - } - - - public void messageTransferred(Message m, DTNHost from, DTNHost to, + + this.nrofAborted++; + } + + + public void messageTransferred(Message m, DTNHost from, DTNHost to, boolean finalTarget) { if (isWarmupID(m.getId())) { return; } - - this.nrofRelayed++; - if (finalTarget) { - this.latencies.add(getSimTime() - - this.creationTimes.get(m.getId()) ); - this.nrofDelivered++; - this.hopCounts.add(m.getHops().size() - 1); - - if (m.isResponse()) { - this.rtt.add(getSimTime() - m.getRequest().getCreationTime()); - this.nrofResponseDelivered++; - } - } - } - - + + this.nrofRelayed++; + if (finalTarget) { + this.latencies.add(getSimTime() - + this.creationTimes.get(m.getId()) ); + this.nrofDelivered++; + this.hopCounts.add(m.getHops().size() - 1); + + if (m.isResponse()) { + this.rtt.add(getSimTime() - m.getRequest().getCreationTime()); + this.nrofResponseDelivered++; + } + } + } + + public void newMessage(Message m) { if (isWarmup()) { addWarmupID(m.getId()); return; } - - this.creationTimes.put(m.getId(), getSimTime()); - this.nrofCreated++; - if (m.getResponseSize() > 0) { - this.nrofResponseReqCreated++; - } - } - - + + this.creationTimes.put(m.getId(), getSimTime()); + this.nrofCreated++; + if (m.getResponseSize() > 0) { + this.nrofResponseReqCreated++; + } + } + + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { if (isWarmupID(m.getId())) { return; } - - this.nrofStarted++; - } - - - @Override - public void done() { - write("Message stats for scenario " + getScenarioName() + - "\nsim_time: " + format(getSimTime())); - double deliveryProb = 0; // delivery probability - double responseProb = 0; // request-response success probability - double overHead = Double.NaN; // overhead ratio - - if (this.nrofCreated > 0) { - deliveryProb = (1.0 * this.nrofDelivered) / this.nrofCreated; - } - if (this.nrofDelivered > 0) { - overHead = (1.0 * (this.nrofRelayed - this.nrofDelivered)) / - this.nrofDelivered; - } - if (this.nrofResponseReqCreated > 0) { - responseProb = (1.0* this.nrofResponseDelivered) / - this.nrofResponseReqCreated; - } - - String statsText = "created: " + this.nrofCreated + - "\nstarted: " + this.nrofStarted + + + this.nrofStarted++; + } + + + @Override + public void done() { + write("Message stats for scenario " + getScenarioName() + + "\nsim_time: " + format(getSimTime())); + double deliveryProb = 0; // delivery probability + double responseProb = 0; // request-response success probability + double overHead = Double.NaN; // overhead ratio + + if (this.nrofCreated > 0) { + deliveryProb = (1.0 * this.nrofDelivered) / this.nrofCreated; + } + if (this.nrofDelivered > 0) { + overHead = (1.0 * (this.nrofRelayed - this.nrofDelivered)) / + this.nrofDelivered; + } + if (this.nrofResponseReqCreated > 0) { + responseProb = (1.0* this.nrofResponseDelivered) / + this.nrofResponseReqCreated; + } + + String statsText = "created: " + this.nrofCreated + + "\nstarted: " + this.nrofStarted + "\nrelayed: " + this.nrofRelayed + - "\naborted: " + this.nrofAborted + - "\ndropped: " + this.nrofDropped + - "\nremoved: " + this.nrofRemoved + + "\naborted: " + this.nrofAborted + + "\ndropped: " + this.nrofDropped + + "\nremoved: " + this.nrofRemoved + "\ndelivered: " + this.nrofDelivered + - "\ndelivery_prob: " + format(deliveryProb) + - "\nresponse_prob: " + format(responseProb) + - "\noverhead_ratio: " + format(overHead) + - "\nlatency_avg: " + getAverage(this.latencies) + - "\nlatency_med: " + getMedian(this.latencies) + - "\nhopcount_avg: " + getIntAverage(this.hopCounts) + - "\nhopcount_med: " + getIntMedian(this.hopCounts) + - "\nbuffertime_avg: " + getAverage(this.msgBufferTime) + - "\nbuffertime_med: " + getMedian(this.msgBufferTime) + - "\nrtt_avg: " + getAverage(this.rtt) + - "\nrtt_med: " + getMedian(this.rtt) - ; - - write(statsText); - super.done(); - } - -} + "\ndelivery_prob: " + format(deliveryProb) + + "\nresponse_prob: " + format(responseProb) + + "\noverhead_ratio: " + format(overHead) + + "\nlatency_avg: " + getAverage(this.latencies) + + "\nlatency_med: " + getMedian(this.latencies) + + "\nhopcount_avg: " + getIntAverage(this.hopCounts) + + "\nhopcount_med: " + getIntMedian(this.hopCounts) + + "\nbuffertime_avg: " + getAverage(this.msgBufferTime) + + "\nbuffertime_med: " + getMedian(this.msgBufferTime) + + "\nrtt_avg: " + getAverage(this.rtt) + + "\nrtt_med: " + getMedian(this.rtt) + ; + + write(statsText); + super.done(); + } + +} diff --git a/report/MovementNs2Report.java b/report/MovementNs2Report.java index 7286eaec0..a6692eedb 100644 --- a/report/MovementNs2Report.java +++ b/report/MovementNs2Report.java @@ -1,89 +1,89 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import core.Coord; import core.DTNHost; import core.MovementListener; import core.Settings; - -/** - * Movement report that generates suitable movement data for ns-2 simulator - * as described in + +/** + * Movement report that generates suitable movement data for ns-2 simulator + * as described in * http://www.isi.edu/nsnam/ns/doc/node174.html. - * This report ignores the warm up settings. - */ -public class MovementNs2Report extends Report implements MovementListener { - /** node array's name -setting id ({@value})*/ - public static final String NODE_ARR_S = "nodeArray"; - /** ns command -setting id ({@value}) */ - public static final String NS_CMD_S = "nsCmd"; - /** default value for the array name ({@value})*/ - public static final String DEF_NODE_ARRAY = "$node_"; - /** default value for the ns command ({@value})*/ - public static final String DEF_NS_CMD = "$ns_"; - - /** a value "close enough" to zero ({@value}). Used for fixing zero values*/ - public static final double EPSILON = 0.00001; - /** formatting string for coordinate values ({@value})*/ - public static final String COORD_FORMAT = "%.5f"; - - private String nodeArray; - private String nsCmd; - - /** - * Constructor. Reads {@link #NODE_ARR_S} and {@link #NS_CMD_S} settings - * and uses those values as the name of the node array and ns command. - * If the values aren't present, default values of - * {@value DEF_NODE_ARRAY} and - * {@value DEF_NS_CMD} are used. - */ - public MovementNs2Report() { - Settings settings = getSettings(); - - if (settings.contains(NODE_ARR_S)) { - nodeArray = settings.getSetting(NODE_ARR_S); - } - else { - nodeArray = DEF_NODE_ARRAY; - } - if (settings.contains(NS_CMD_S)) { - nsCmd = settings.getSetting(NS_CMD_S); - } - else { - nsCmd = DEF_NS_CMD; - } - - init(); - } - - public void initialLocation(DTNHost host, Coord location) { - int index = host.getAddress(); - write(nodeArray + "("+ index + ") set X_ " + fix(location.getX())); - write(nodeArray + "("+ index + ") set Y_ " + fix(location.getY())); - write(nodeArray + "("+ index + ") set Z_ 0"); - } - - public void newDestination(DTNHost host, Coord dst, double speed) { - int index = host.getAddress(); - double time = getSimTime(); - - write(nsCmd + " at " + time + " \"\\" + nodeArray + "(" + index + ")" + - " setdest " + fix(dst.getX()) + " " + fix(dst.getY()) + - " " + speed + "\""); - } - - /** - * Fixes and formats coordinate values suitable for Ns2 module. - * I.e. converts zero-values to {@value EPSILON} and formats values - * with {@link #COORD_FORMAT}. - * @param val The value to fix - * @return The fixed value - */ - private String fix(double val) { - val = val == 0 ? EPSILON : val; - return String.format(COORD_FORMAT, val); - } -} + * This report ignores the warm up settings. + */ +public class MovementNs2Report extends Report implements MovementListener { + /** node array's name -setting id ({@value})*/ + public static final String NODE_ARR_S = "nodeArray"; + /** ns command -setting id ({@value}) */ + public static final String NS_CMD_S = "nsCmd"; + /** default value for the array name ({@value})*/ + public static final String DEF_NODE_ARRAY = "$node_"; + /** default value for the ns command ({@value})*/ + public static final String DEF_NS_CMD = "$ns_"; + + /** a value "close enough" to zero ({@value}). Used for fixing zero values*/ + public static final double EPSILON = 0.00001; + /** formatting string for coordinate values ({@value})*/ + public static final String COORD_FORMAT = "%.5f"; + + private String nodeArray; + private String nsCmd; + + /** + * Constructor. Reads {@link #NODE_ARR_S} and {@link #NS_CMD_S} settings + * and uses those values as the name of the node array and ns command. + * If the values aren't present, default values of + * {@value DEF_NODE_ARRAY} and + * {@value DEF_NS_CMD} are used. + */ + public MovementNs2Report() { + Settings settings = getSettings(); + + if (settings.contains(NODE_ARR_S)) { + nodeArray = settings.getSetting(NODE_ARR_S); + } + else { + nodeArray = DEF_NODE_ARRAY; + } + if (settings.contains(NS_CMD_S)) { + nsCmd = settings.getSetting(NS_CMD_S); + } + else { + nsCmd = DEF_NS_CMD; + } + + init(); + } + + public void initialLocation(DTNHost host, Coord location) { + int index = host.getAddress(); + write(nodeArray + "("+ index + ") set X_ " + fix(location.getX())); + write(nodeArray + "("+ index + ") set Y_ " + fix(location.getY())); + write(nodeArray + "("+ index + ") set Z_ 0"); + } + + public void newDestination(DTNHost host, Coord dst, double speed) { + int index = host.getAddress(); + double time = getSimTime(); + + write(nsCmd + " at " + time + " \"\\" + nodeArray + "(" + index + ")" + + " setdest " + fix(dst.getX()) + " " + fix(dst.getY()) + + " " + speed + "\""); + } + + /** + * Fixes and formats coordinate values suitable for Ns2 module. + * I.e. converts zero-values to {@value EPSILON} and formats values + * with {@link #COORD_FORMAT}. + * @param val The value to fix + * @return The fixed value + */ + private String fix(double val) { + val = val == 0 ? EPSILON : val; + return String.format(COORD_FORMAT, val); + } +} diff --git a/report/PingAppReporter.java b/report/PingAppReporter.java index ad780a34f..46921e6a4 100644 --- a/report/PingAppReporter.java +++ b/report/PingAppReporter.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package report; @@ -13,19 +13,19 @@ /** * Reporter for the PingApplication. Counts the number of pings * and pongs sent and received. Calculates success probabilities. - * + * * @author teemuk */ public class PingAppReporter extends Report implements ApplicationListener { - + private int pingsSent=0, pingsReceived=0; private int pongsSent=0, pongsReceived=0; - + public void gotEvent(String event, Object params, Application app, DTNHost host) { // Check that the event is sent by correct application type if (!(app instanceof PingApplication)) return; - + // Increment the counters based on the event type if (event.equalsIgnoreCase("GotPing")) { pingsReceived++; @@ -39,18 +39,18 @@ public void gotEvent(String event, Object params, Application app, if (event.equalsIgnoreCase("SentPing")) { pingsSent++; } - + } - + @Override public void done() { - write("Ping stats for scenario " + getScenarioName() + + write("Ping stats for scenario " + getScenarioName() + "\nsim_time: " + format(getSimTime())); double pingProb = 0; // ping probability double pongProb = 0; // pong probability double successProb = 0; // success probability - + if (this.pingsSent > 0) { pingProb = (1.0 * this.pingsReceived) / this.pingsSent; } @@ -60,16 +60,16 @@ public void done() { if (this.pingsSent > 0) { successProb = (1.0 * this.pongsReceived) / this.pingsSent; } - - String statsText = "pings sent: " + this.pingsSent + - "\npings received: " + this.pingsReceived + + + String statsText = "pings sent: " + this.pingsSent + + "\npings received: " + this.pingsReceived + "\npongs sent: " + this.pongsSent + "\npongs received: " + this.pongsReceived + "\nping delivery prob: " + format(pingProb) + - "\npong delivery prob: " + format(pongProb) + + "\npong delivery prob: " + format(pongProb) + "\nping/pong success prob: " + format(successProb) ; - + write(statsText); super.done(); } diff --git a/report/Report.java b/report/Report.java index 209fec126..11c757825 100644 --- a/report/Report.java +++ b/report/Report.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package report; @@ -22,25 +22,25 @@ /** * Abstract superclass for all reports. All settings defined in this class * can be used for all Report classes. Some reports don't implement intervalled - * reports ({@link #INTERVAL_SETTING}) and will ignore that setting. Most of + * reports ({@link #INTERVAL_SETTING}) and will ignore that setting. Most of * the reports implement warm up feature ({@link #WARMUP_S}) but the * implementations are always report specific. */ public abstract class Report { - /** Name space of the settings that are common to all reports ({@value}). */ + /** Name space of the settings that are common to all reports ({@value}). */ public static final String REPORT_NS = "Report"; - /** The interval (simulated seconds) of creating new settings files + /** The interval (simulated seconds) of creating new settings files * -setting id ({@value}) */ public static final String INTERVAL_SETTING = "interval"; /** The output file path of the report -setting id ({@value})*/ public static final String OUTPUT_SETTING = "output"; - /** Precision of formatted double values - setting id ({@value}). + /** Precision of formatted double values - setting id ({@value}). * Defines the amount of decimals shown in formatted double values. * Default value is {@value #DEF_PRECISION}. */ public static final String PRECISION_SETTING = "precision"; /** Default precision of formatted double values */ public static final int DEF_PRECISION = 4; - /** The default output directory of reports (can be overridden per report + /** The default output directory of reports (can be overridden per report * with {@link Report#OUTPUT_SETTING}) -setting id ({@value})*/ public static final String REPORTDIR_SETTING = "Report.reportDir"; /** Warm up period -setting id ({@value}). Defines how many seconds from @@ -52,7 +52,7 @@ public abstract class Report { /** Suffix of report files without explicit output */ public static final String OUT_SUFFIX = ".txt"; /** Suffix for reports that are created on n second intervals */ - public static final String INTERVALLED_FORMAT ="%04d" + OUT_SUFFIX; + public static final String INTERVALLED_FORMAT ="%04d" + OUT_SUFFIX; /** The print writer used to write output. See {@link #write(String)} */ protected PrintWriter out; /** String value for values that could not be calculated */ @@ -61,13 +61,13 @@ public abstract class Report { private int precision; protected int warmupTime; protected Set warmupIDs; - + private int lastOutputSuffix; private double outputInterval; private double lastReportTime; private String outFileName; private String scenarioName; - + /** * Constructor. * Looks for a className.output setting in the Settings and @@ -82,13 +82,13 @@ public Report(){ Settings settings = new Settings(); scenarioName = settings.valueFillString(settings.getSetting( SimScenario.SCENARIO_NS + "." + SimScenario.NAME_S)); - + settings = getSettings(); - + if (settings.contains(INTERVAL_SETTING)) { outputInterval = settings.getDouble(INTERVAL_SETTING); } - + if (settings.contains(WARMUP_S)) { this.warmupTime = settings.getInt(WARMUP_S); } @@ -96,7 +96,7 @@ public Report(){ this.warmupTime = 0; } - + if (settings.contains(PRECISION_SETTING)) { precision = settings.getInt(PRECISION_SETTING); if (precision < 0) { @@ -106,7 +106,7 @@ public Report(){ else { precision = DEF_PRECISION; } - + if (settings.contains(OUTPUT_SETTING)) { outFileName = settings.getSetting(OUTPUT_SETTING); // fill value place holders in the name @@ -119,14 +119,14 @@ public Report(){ if (!outDir.endsWith("/")) { outDir += "/"; // make sure dir ends with directory delimiter } - outFileName = outDir + scenarioName + + outFileName = outDir + scenarioName + "_" + this.getClass().getSimpleName(); if (outputInterval == -1) { outFileName += OUT_SUFFIX; // no intervalled reports } - + } - + checkDirExistence(outFileName); } @@ -138,15 +138,15 @@ public Report(){ private void checkDirExistence(String outFileName) { File outFile = new File(outFileName); File outDir = outFile.getParentFile(); - + if (outDir != null && !outDir.exists()) { if (!createDirs(outDir)) { - throw new SimError("Couldn't create report directory '" + + throw new SimError("Couldn't create report directory '" + outDir.getAbsolutePath()+"'"); } } } - + /** * Recursively creates a directory structure * @param directory The directory to create @@ -169,7 +169,7 @@ private boolean createDirs(File directory) { } } } - + /** * Initializes the report output. Method is called in the beginning of * every new report file. Subclasses must call this method first in their @@ -177,7 +177,7 @@ private boolean createDirs(File directory) { */ protected void init() { this.lastReportTime = getSimTime(); - + if (outputInterval > 0) { createSuffixedOutput(outFileName); } @@ -185,7 +185,7 @@ protected void init() { createOutput(outFileName); } } - + /** * Creates a new output file * @param outFileName Name (&path) of the file to create @@ -194,11 +194,11 @@ private void createOutput(String outFileName) { try { this.out = new PrintWriter(new FileWriter(outFileName)); } catch (IOException e) { - throw new SimError("Couldn't open file '" + outFileName + + throw new SimError("Couldn't open file '" + outFileName + "' for report output\n" + e.getMessage(), e); - } + } } - + /** * Creates a number-suffixed output file with increasing number suffix * @param outFileName Prefix of the output file's name @@ -209,23 +209,23 @@ private void createSuffixedOutput(String outFileName) { createOutput(outFileName+suffix); this.lastOutputSuffix++; } - + /** * This method should be called before every new (complete) event the * report logs. If the report has no meaningful use for multiple reports, - * the call can be omitted (then only single output file will be generated) + * the call can be omitted (then only single output file will be generated) */ protected void newEvent() { if (this.outputInterval <= 0) { return; } - + if (getSimTime() > this.lastReportTime + this.outputInterval) { done(); // finalize the old file init(); // init the new file } } - + /** * Writes a line to report using defined prefix and {@link #out} writer. * @param txt Line to write @@ -237,7 +237,7 @@ protected void write(String txt) { } out.println(prefix + txt); } - + /** * Formats a double value according to current precision setting (see * {@link #PRECISION_SETTING}) and returns it in a string. @@ -247,7 +247,7 @@ protected void write(String txt) { protected String format(double value) { return String.format("%." + precision + "f", value); } - + /** * Sets a prefix that will be inserted before every line in the report * @param txt Text to use as the prefix @@ -255,7 +255,7 @@ protected String format(double value) { protected void setPrefix(String txt) { this.prefix = txt; } - + /** * Returns the name of the scenario as read from the settings * @return the name of the scenario as read from the settings @@ -263,7 +263,7 @@ protected void setPrefix(String txt) { protected String getScenarioName() { return this.scenarioName; } - + /** * Returns the current simulation time from the SimClock * @return the current simulation time from the SimClock @@ -271,7 +271,7 @@ protected String getScenarioName() { protected double getSimTime() { return SimClock.getTime(); } - + /** * Returns true if the warm up period is still ongoing (simTime < warmup) * @return true if the warm up period is still ongoing, false if not @@ -279,7 +279,7 @@ protected double getSimTime() { protected boolean isWarmup() { return this.warmupTime > SimClock.getTime(); } - + /** * Adds a new ID to the warm up ID set * @param id The ID @@ -288,10 +288,10 @@ protected void addWarmupID(String id) { if (this.warmupIDs == null) { // lazy creation of the Set this.warmupIDs = new HashSet(); } - + this.warmupIDs.add(id); } - + /** * Removes a warm up ID from the warm up ID set * @param id The ID to remove @@ -299,7 +299,7 @@ protected void addWarmupID(String id) { protected void removeWarmupID(String id) { this.warmupIDs.remove(id); } - + /** * Returns true if the given ID is in the warm up ID set * @param id The ID @@ -309,10 +309,10 @@ protected boolean isWarmupID(String id) { if (this.warmupIDs == null || this.warmupIDs.size() == 0) { return false; } - + return this.warmupIDs.contains(id); } - + /** * Returns a Settings object initialized for the report class' name space * that uses {@value REPORT_NS} as the secondary name space. @@ -323,23 +323,23 @@ protected Settings getSettings() { s.setSecondaryNamespace(REPORT_NS); return s; } - - /** - * Called when the simulation is done, user requested - * premature termination or intervalled report generating decided - * that it's time for the next report. - */ + + /** + * Called when the simulation is done, user requested + * premature termination or intervalled report generating decided + * that it's time for the next report. + */ public void done() { - if (out != null) { + if (out != null) { out.close(); - } + } } - + /** * Returns the average of double values stored in a List or "NaN" for * empty lists. * @param values The list of double values - * @return average of double values stored in the List in a formatted String + * @return average of double values stored in the List in a formatted String */ public String getAverage(List values) { double sum = 0; @@ -350,7 +350,7 @@ public String getAverage(List values) { for (double dValue : values) { sum += dValue; } - + return format(sum / values.size()); } @@ -364,10 +364,10 @@ public String getIntAverage(List values) { List dValues = new ArrayList(values.size()); for (int i : values) { dValues.add((double)i); - } + } return getAverage(dValues); } - + /** * Returns the median of double values stored in a List * @param values The list of double values @@ -378,11 +378,11 @@ public String getMedian(List values) { if (values.size() == 0) { return NAN; } - + Collections.sort(values); return format(values.get(values.size()/2)); } - + /** * Returns the median of integer values stored in a List * @param values The list of values @@ -393,14 +393,14 @@ public int getIntMedian(List values) { if (values.size() == 0) { return 0; } - + Collections.sort(values); return values.get(values.size()/2); } - - /** + + /** * Returns the variance of the values in the List. - * + * * @param values The list of values * @return The variance of the values in the list or "NaN" if the list is * empty. @@ -416,5 +416,5 @@ public String getVariance(List values) { E_X = sum / values.size(); return format(sum2/values.size() - (E_X*E_X)); } - + } diff --git a/report/TotalContactTimeReport.java b/report/TotalContactTimeReport.java index 526074591..49359f2f4 100644 --- a/report/TotalContactTimeReport.java +++ b/report/TotalContactTimeReport.java @@ -1,79 +1,79 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package report; - +package report; + import java.util.List; import core.DTNHost; import core.UpdateListener; - -/** - * Report for total amount of contact times among hosts. Reports how long all - * nodes have been in contact with some other node. Supports - * {@link ContactTimesReport#GRANULARITY} setting. If update interval is - * smaller than 1.0 seconds, time stamps may start to drift. Reported values + +/** + * Report for total amount of contact times among hosts. Reports how long all + * nodes have been in contact with some other node. Supports + * {@link ContactTimesReport#GRANULARITY} setting. If update interval is + * smaller than 1.0 seconds, time stamps may start to drift. Reported values * still correspond to reported times. Connections that started during the - * warmup period are ignored. - */ -public class TotalContactTimeReport extends ContactTimesReport implements - UpdateListener { - - /** The header of every report file */ - public static final String HEADER = "# time totalContactTime"; - /** cumulative contact times of all disconnected contacts */ - private double oldContactTimes; - /** sim time of last report writing */ - private double lastWrite; - /** last reported time count (to suppress duplicates) */ - private double lastReportedTime; - - public void init() { - super.init(); - write(HEADER); - this.oldContactTimes = 0; - this.lastReportedTime = 0; - this.lastWrite = getSimTime(); - } - - @Override - public void hostsDisconnected(DTNHost host1, DTNHost host2) { - newEvent(); - ConnectionInfo ci = removeConnection(host1, host2); - + * warmup period are ignored. + */ +public class TotalContactTimeReport extends ContactTimesReport implements + UpdateListener { + + /** The header of every report file */ + public static final String HEADER = "# time totalContactTime"; + /** cumulative contact times of all disconnected contacts */ + private double oldContactTimes; + /** sim time of last report writing */ + private double lastWrite; + /** last reported time count (to suppress duplicates) */ + private double lastReportedTime; + + public void init() { + super.init(); + write(HEADER); + this.oldContactTimes = 0; + this.lastReportedTime = 0; + this.lastWrite = getSimTime(); + } + + @Override + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + newEvent(); + ConnectionInfo ci = removeConnection(host1, host2); + if (ci == null) { return; // connection started during the warm up period } - - oldContactTimes += ci.getConnectionTime(); - } - - /** - * Reports total contact time if more time than defined with setting - * {@link ContactTimesReport#GRANULARITY} has passed. Method is called - * on every update cycle. - */ - public void updated(List hosts) { - double simTime = getSimTime(); - if (simTime - lastWrite < granularity || isWarmup()) { - return; // shouldn't report yet - } - lastWrite = simTime; - - // count also the times for connections that are still up - double othersTime = 0; - for (ConnectionInfo oth : this.connections.values()) { - othersTime += oth.getConnectionTime(); - } - - double totalTime = oldContactTimes + othersTime; - - if (lastReportedTime == totalTime) { - return; // don't report duplicate times - } - - write(format(simTime) + " " + format(totalTime)); - lastReportedTime = totalTime; - } -} + + oldContactTimes += ci.getConnectionTime(); + } + + /** + * Reports total contact time if more time than defined with setting + * {@link ContactTimesReport#GRANULARITY} has passed. Method is called + * on every update cycle. + */ + public void updated(List hosts) { + double simTime = getSimTime(); + if (simTime - lastWrite < granularity || isWarmup()) { + return; // shouldn't report yet + } + lastWrite = simTime; + + // count also the times for connections that are still up + double othersTime = 0; + for (ConnectionInfo oth : this.connections.values()) { + othersTime += oth.getConnectionTime(); + } + + double totalTime = oldContactTimes + othersTime; + + if (lastReportedTime == totalTime) { + return; // don't report duplicate times + } + + write(format(simTime) + " " + format(totalTime)); + lastReportedTime = totalTime; + } +} diff --git a/report/TotalEncountersReport.java b/report/TotalEncountersReport.java index dbcba20b9..d8dd2bb2f 100644 --- a/report/TotalEncountersReport.java +++ b/report/TotalEncountersReport.java @@ -1,75 +1,75 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package report; - -import java.util.List; - -import core.ConnectionListener; -import core.DTNHost; -import core.UpdateListener; - -/** - * A report of the distribution of how many encounters (contacts) a node has had - * - * @author Frans Ekman - */ -public class TotalEncountersReport extends Report implements ConnectionListener, - UpdateListener { - - private int[] encounters; - - public TotalEncountersReport() { - - } - - public void hostsConnected(DTNHost host1, DTNHost host2) { - if (encounters == null) { - return; - } - encounters[host1.getAddress()]++; - encounters[host2.getAddress()]++; - } - - public void hostsDisconnected(DTNHost host1, DTNHost host2) {} - - public void updated(List hosts) { - if (encounters == null) { - encounters = new int[hosts.size()]; - } - } - - @Override - public void done() { - - int maxEncounters = -1; - for (int i=0; i maxEncounters) { - maxEncounters = encounters[i]; - } - } - - int[] distribution = new int[maxEncounters + 1]; - - for (int i=0; i hosts) { + if (encounters == null) { + encounters = new int[hosts.size()]; + } + } + + @Override + public void done() { + + int maxEncounters = -1; + for (int i=0; i maxEncounters) { + maxEncounters = encounters[i]; + } + } + + int[] distribution = new int[maxEncounters + 1]; + + for (int i=0; i hosts) { - if (nodeRelationships == null) { - nodeRelationships = new int[hosts.size()][hosts.size()]; - } - } - - @Override - public void done() { - int[] distribution = new int[1000]; - - for (int i=0; i 0) { - count++; - } - } - - int promille = (count * 1000)/nodeRelationships.length; - distribution[promille]++; - } - - // print distribution - for (int i=0; i hosts) { + if (nodeRelationships == null) { + nodeRelationships = new int[hosts.size()][hosts.size()]; + } + } + + @Override + public void done() { + int[] distribution = new int[1000]; + + for (int i=0; i 0) { + count++; + } + } + + int promille = (count * 1000)/nodeRelationships.length; + distribution[promille]++; + } + + // print distribution + for (int i=0; i - - - -Contains all the report classes. Reports can be used to create e.g. statistics -and visualizations of the simulation. All report classes must be in this -package and must extend the {@link report.Report} class so they can be -dynamically loaded to the simulator. The classes to load can be specified -trough {@link core.Settings} class' settings source. See Report class and -classes extending it for details about the settings. - - - \ No newline at end of file + + + + +Contains all the report classes. Reports can be used to create e.g. statistics +and visualizations of the simulation. All report classes must be in this +package and must extend the {@link report.Report} class so they can be +dynamically loaded to the simulator. The classes to load can be specified +trough {@link core.Settings} class' settings source. See Report class and +classes extending it for details about the settings. + + + diff --git a/routing/ActiveRouter.java b/routing/ActiveRouter.java index e42605b9c..d186688a0 100644 --- a/routing/ActiveRouter.java +++ b/routing/ActiveRouter.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; - +package routing; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -22,12 +22,12 @@ import core.NetworkInterface; import core.Settings; import core.SimClock; - -/** - * Superclass of active routers. Contains convenience methods (e.g. - * {@link #getNextMessageToRemove(boolean)}) and watching of sending connections (see - * {@link #update()}). - */ + +/** + * Superclass of active routers. Contains convenience methods (e.g. + * {@link #getNextMessageToRemove(boolean)}) and watching of sending connections (see + * {@link #update()}). + */ public abstract class ActiveRouter extends MessageRouter { /** Delete delivered messages -setting id ({@value}). Boolean valued. * If set to true and final recipient of a message rejects it because it @@ -36,532 +36,532 @@ public abstract class ActiveRouter extends MessageRouter { /** should messages that final recipient marks as delivered be deleted * from message buffer */ protected boolean deleteDelivered; - - /** prefix of all response message IDs */ - public static final String RESPONSE_PREFIX = "R_"; - /** how often TTL check (discarding old messages) is performed */ - public static int TTL_CHECK_INTERVAL = 60; - /** connection(s) that are currently used for sending */ - protected ArrayList sendingConnections; - /** sim time when the last TTL check was done */ + + /** prefix of all response message IDs */ + public static final String RESPONSE_PREFIX = "R_"; + /** how often TTL check (discarding old messages) is performed */ + public static int TTL_CHECK_INTERVAL = 60; + /** connection(s) that are currently used for sending */ + protected ArrayList sendingConnections; + /** sim time when the last TTL check was done */ private double lastTtlCheck; - + private MessageTransferAcceptPolicy policy; - private EnergyModel energy; - - /** - * Constructor. Creates a new message router based on the settings in - * the given Settings object. - * @param s The settings object - */ - public ActiveRouter(Settings s) { + private EnergyModel energy; + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public ActiveRouter(Settings s) { super(s); - + this.policy = new MessageTransferAcceptPolicy(s); - + this.deleteDelivered = s.getBoolean(DELETE_DELIVERED_S, false); - + if (s.contains(EnergyModel.INIT_ENERGY_S)) { this.energy = new EnergyModel(s); } else { this.energy = null; /* no energy model */ - } - } - - /** - * Copy constructor. - * @param r The router prototype where setting values are copied from - */ - protected ActiveRouter(ActiveRouter r) { + } + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected ActiveRouter(ActiveRouter r) { super(r); this.deleteDelivered = r.deleteDelivered; this.policy = r.policy; - this.energy = (r.energy != null ? r.energy.replicate() : null); - } - - @Override - public void init(DTNHost host, List mListeners) { - super.init(host, mListeners); - this.sendingConnections = new ArrayList(1); - this.lastTtlCheck = 0; - } - - /** + this.energy = (r.energy != null ? r.energy.replicate() : null); + } + + @Override + public void init(DTNHost host, List mListeners) { + super.init(host, mListeners); + this.sendingConnections = new ArrayList(1); + this.lastTtlCheck = 0; + } + + /** * Called when a connection's state changes. If energy modeling is enabled, * and a new connection is created to this node, reduces the energy for the * device discovery (scan response) amount - * @param @con The connection whose state changed - */ - @Override + * @param @con The connection whose state changed + */ + @Override public void changedConnection(Connection con) { if (this.energy != null && con.isUp() && !con.isInitiator(getHost())) { this.energy.reduceDiscoveryEnergy(); } - } - - @Override - public boolean requestDeliverableMessages(Connection con) { - if (isTransferring()) { - return false; - } - + } + + @Override + public boolean requestDeliverableMessages(Connection con) { + if (isTransferring()) { + return false; + } + DTNHost other = con.getOtherNode(getHost()); - /* do a copy to avoid concurrent modification exceptions + /* do a copy to avoid concurrent modification exceptions * (startTransfer may remove messages) */ - ArrayList temp = - new ArrayList(this.getMessageCollection()); - for (Message m : temp) { - if (other == m.getTo()) { - if (startTransfer(m, con) == RCV_OK) { - return true; - } - } - } - return false; - } - - @Override - public boolean createNewMessage(Message m) { - makeRoomForNewMessage(m.getSize()); - return super.createNewMessage(m); - } - - @Override - public int receiveMessage(Message m, DTNHost from) { - int recvCheck = checkReceiving(m, from); - if (recvCheck != RCV_OK) { - return recvCheck; - } - - // seems OK, start receiving the message - return super.receiveMessage(m, from); - } - - @Override - public Message messageTransferred(String id, DTNHost from) { - Message m = super.messageTransferred(id, from); + ArrayList temp = + new ArrayList(this.getMessageCollection()); + for (Message m : temp) { + if (other == m.getTo()) { + if (startTransfer(m, con) == RCV_OK) { + return true; + } + } + } + return false; + } + + @Override + public boolean createNewMessage(Message m) { + makeRoomForNewMessage(m.getSize()); + return super.createNewMessage(m); + } + + @Override + public int receiveMessage(Message m, DTNHost from) { + int recvCheck = checkReceiving(m, from); + if (recvCheck != RCV_OK) { + return recvCheck; + } + + // seems OK, start receiving the message + return super.receiveMessage(m, from); + } + + @Override + public Message messageTransferred(String id, DTNHost from) { + Message m = super.messageTransferred(id, from); /** * N.B. With application support the following if-block - * becomes obsolete, and the response size should be configured + * becomes obsolete, and the response size should be configured * to zero. - */ - // check if msg was for this host and a response was requested - if (m.getTo() == getHost() && m.getResponseSize() > 0) { + */ + // check if msg was for this host and a response was requested + if (m.getTo() == getHost() && m.getResponseSize() > 0) { // generate a response message - Message res = new Message(this.getHost(),m.getFrom(), + Message res = new Message(this.getHost(),m.getFrom(), RESPONSE_PREFIX+m.getId(), m.getResponseSize()); - this.createNewMessage(res); - this.getMessage(RESPONSE_PREFIX+m.getId()).setRequest(m); - } - - return m; - } - - /** - * Returns a list of connections this host currently has with other hosts. - * @return a list of connections this host currently has with other hosts - */ - protected List getConnections() { - return getHost().getConnections(); - } - - /** - * Tries to start a transfer of message using a connection. Is starting - * succeeds, the connection is added to the watch list of active connections - * @param m The message to transfer - * @param con The connection to use - * @return the value returned by - * {@link Connection#startTransfer(DTNHost, Message)} - */ - protected int startTransfer(Message m, Connection con) { + this.createNewMessage(res); + this.getMessage(RESPONSE_PREFIX+m.getId()).setRequest(m); + } + + return m; + } + + /** + * Returns a list of connections this host currently has with other hosts. + * @return a list of connections this host currently has with other hosts + */ + protected List getConnections() { + return getHost().getConnections(); + } + + /** + * Tries to start a transfer of message using a connection. Is starting + * succeeds, the connection is added to the watch list of active connections + * @param m The message to transfer + * @param con The connection to use + * @return the value returned by + * {@link Connection#startTransfer(DTNHost, Message)} + */ + protected int startTransfer(Message m, Connection con) { int retVal; - + if (!con.isReadyForTransfer()) { return TRY_LATER_BUSY; } - - if (!policy.acceptSending(getHost(), + + if (!policy.acceptSending(getHost(), con.getOtherNode(getHost()), con, m)) { return MessageRouter.DENIED_POLICY; } - - retVal = con.startTransfer(getHost(), m); - if (retVal == RCV_OK) { // started transfer - addToSendingConnections(con); + + retVal = con.startTransfer(getHost(), m); + if (retVal == RCV_OK) { // started transfer + addToSendingConnections(con); } - else if (deleteDelivered && retVal == DENIED_OLD && + else if (deleteDelivered && retVal == DENIED_OLD && m.getTo() == con.getOtherNode(this.getHost())) { /* final recipient has already received the msg -> delete it */ this.deleteMessage(m.getId(), false); - } - - return retVal; - } - - /** - * Makes rudimentary checks (that we have at least one message and one - * connection) about can this router start transfer. - * @return True if router can start transfer, false if not - */ - protected boolean canStartTransfer() { - if (this.getNrofMessages() == 0) { - return false; - } - if (this.getConnections().size() == 0) { - return false; - } - - return true; - } - - /** - * Checks if router "wants" to start receiving message (i.e. router - * isn't transferring, doesn't have the message and has room for it). - * @param m The message to check - * @return A return code similar to - * {@link MessageRouter#receiveMessage(Message, DTNHost)}, i.e. - * {@link MessageRouter#RCV_OK} if receiving seems to be OK, - * TRY_LATER_BUSY if router is transferring, DENIED_OLD if the router - * is already carrying the message or it has been delivered to - * this router (as final recipient), or DENIED_NO_SPACE if the message - * does not fit into buffer - */ - protected int checkReceiving(Message m, DTNHost from) { - if (isTransferring()) { - return TRY_LATER_BUSY; // only one connection at a time - } - + } + + return retVal; + } + + /** + * Makes rudimentary checks (that we have at least one message and one + * connection) about can this router start transfer. + * @return True if router can start transfer, false if not + */ + protected boolean canStartTransfer() { + if (this.getNrofMessages() == 0) { + return false; + } + if (this.getConnections().size() == 0) { + return false; + } + + return true; + } + + /** + * Checks if router "wants" to start receiving message (i.e. router + * isn't transferring, doesn't have the message and has room for it). + * @param m The message to check + * @return A return code similar to + * {@link MessageRouter#receiveMessage(Message, DTNHost)}, i.e. + * {@link MessageRouter#RCV_OK} if receiving seems to be OK, + * TRY_LATER_BUSY if router is transferring, DENIED_OLD if the router + * is already carrying the message or it has been delivered to + * this router (as final recipient), or DENIED_NO_SPACE if the message + * does not fit into buffer + */ + protected int checkReceiving(Message m, DTNHost from) { + if (isTransferring()) { + return TRY_LATER_BUSY; // only one connection at a time + } + if ( hasMessage(m.getId()) || isDeliveredMessage(m) || - super.isBlacklistedMessage(m.getId())) { - return DENIED_OLD; // already seen this message -> reject it - } - + super.isBlacklistedMessage(m.getId())) { + return DENIED_OLD; // already seen this message -> reject it + } + if (m.getTtl() <= 0 && m.getTo() != getHost()) { /* TTL has expired and this host is not the final recipient */ - return DENIED_TTL; - } + return DENIED_TTL; + } if (energy != null && energy.getEnergy() <= 0) { return MessageRouter.DENIED_LOW_RESOURCES; } - + if (!policy.acceptReceiving(from, getHost(), m)) { return MessageRouter.DENIED_POLICY; } - - /* remove oldest messages but not the ones being sent */ - if (!makeRoomForMessage(m.getSize())) { - return DENIED_NO_SPACE; // couldn't fit into buffer -> reject - } - - return RCV_OK; - } - - /** - * Removes messages from the buffer (oldest first) until - * there's enough space for the new message. - * @param size Size of the new message - * transferred, the transfer is aborted before message is removed - * @return True if enough space could be freed, false if not - */ - protected boolean makeRoomForMessage(int size){ - if (size > this.getBufferSize()) { - return false; // message too big for the buffer - } - - int freeBuffer = this.getFreeBufferSize(); - /* delete messages from the buffer until there's enough space */ - while (freeBuffer < size) { - Message m = getNextMessageToRemove(true); // don't remove msgs being sent - - if (m == null) { - return false; // couldn't remove any more messages - } - - /* delete message from the buffer as "drop" */ - deleteMessage(m.getId(), true); - freeBuffer += m.getSize(); - } - - return true; - } - - /** - * Drops messages whose TTL is less than zero. - */ - protected void dropExpiredMessages() { - Message[] messages = getMessageCollection().toArray(new Message[0]); - for (int i=0; i messages = this.getMessageCollection(); - Message oldest = null; - for (Message m : messages) { - - if (excludeMsgBeingSent && isSending(m.getId())) { - continue; // skip the message(s) that router is sending - } - - if (oldest == null ) { - oldest = m; - } - else if (oldest.getReceiveTime() > m.getReceiveTime()) { - oldest = m; - } - } - - return oldest; - } - - /** - * Returns a list of message-connections tuples of the messages whose - * recipient is some host that we're connected to at the moment. - * @return a list of message-connections tuples - */ - protected List> getMessagesForConnected() { - if (getNrofMessages() == 0 || getConnections().size() == 0) { - /* no messages -> empty list */ - return new ArrayList>(0); - } - - List> forTuples = - new ArrayList>(); - for (Message m : getMessageCollection()) { - for (Connection con : getConnections()) { - DTNHost to = con.getOtherNode(getHost()); - if (m.getTo() == to) { - forTuples.add(new Tuple(m,con)); - } - } - } - - return forTuples; - } - - /** - * Tries to send messages for the connections that are mentioned - * in the Tuples in the order they are in the list until one of - * the connections starts transferring or all tuples have been tried. - * @param tuples The tuples to try - * @return The tuple whose connection accepted the message or null if - * none of the connections accepted the message that was meant for them. - */ - protected Tuple tryMessagesForConnected( - List> tuples) { - if (tuples.size() == 0) { - return null; - } - - for (Tuple t : tuples) { - Message m = t.getKey(); - Connection con = t.getValue(); - if (startTransfer(m, con) == RCV_OK) { - return t; - } - } - - return null; - } - - /** - * Goes trough the messages until the other node accepts one - * for receiving (or doesn't accept any). If a transfer is started, the - * connection is included in the list of sending connections. - * @param con Connection trough which the messages are sent - * @param messages A list of messages to try - * @return The message whose transfer was started or null if no - * transfer was started. - */ - protected Message tryAllMessages(Connection con, List messages) { - for (Message m : messages) { - int retVal = startTransfer(m, con); - if (retVal == RCV_OK) { - return m; // accepted a message, don't try others - } - else if (retVal > 0) { - return null; // should try later -> don't bother trying others - } - } - - return null; // no message was accepted - } - - /** - * Tries to send all given messages to all given connections. Connections - * are first iterated in the order they are in the list and for every - * connection, the messages are tried in the order they are in the list. - * Once an accepting connection is found, no other connections or messages - * are tried. - * @param messages The list of Messages to try - * @param connections The list of Connections to try - * @return The connections that started a transfer or null if no connection - * accepted a message. - */ - protected Connection tryMessagesToConnections(List messages, - List connections) { - for (int i=0, n=connections.size(); i connections = getConnections(); - if (connections.size() == 0 || this.getNrofMessages() == 0) { - return null; - } - - List messages = + + /* remove oldest messages but not the ones being sent */ + if (!makeRoomForMessage(m.getSize())) { + return DENIED_NO_SPACE; // couldn't fit into buffer -> reject + } + + return RCV_OK; + } + + /** + * Removes messages from the buffer (oldest first) until + * there's enough space for the new message. + * @param size Size of the new message + * transferred, the transfer is aborted before message is removed + * @return True if enough space could be freed, false if not + */ + protected boolean makeRoomForMessage(int size){ + if (size > this.getBufferSize()) { + return false; // message too big for the buffer + } + + int freeBuffer = this.getFreeBufferSize(); + /* delete messages from the buffer until there's enough space */ + while (freeBuffer < size) { + Message m = getNextMessageToRemove(true); // don't remove msgs being sent + + if (m == null) { + return false; // couldn't remove any more messages + } + + /* delete message from the buffer as "drop" */ + deleteMessage(m.getId(), true); + freeBuffer += m.getSize(); + } + + return true; + } + + /** + * Drops messages whose TTL is less than zero. + */ + protected void dropExpiredMessages() { + Message[] messages = getMessageCollection().toArray(new Message[0]); + for (int i=0; i messages = this.getMessageCollection(); + Message oldest = null; + for (Message m : messages) { + + if (excludeMsgBeingSent && isSending(m.getId())) { + continue; // skip the message(s) that router is sending + } + + if (oldest == null ) { + oldest = m; + } + else if (oldest.getReceiveTime() > m.getReceiveTime()) { + oldest = m; + } + } + + return oldest; + } + + /** + * Returns a list of message-connections tuples of the messages whose + * recipient is some host that we're connected to at the moment. + * @return a list of message-connections tuples + */ + protected List> getMessagesForConnected() { + if (getNrofMessages() == 0 || getConnections().size() == 0) { + /* no messages -> empty list */ + return new ArrayList>(0); + } + + List> forTuples = + new ArrayList>(); + for (Message m : getMessageCollection()) { + for (Connection con : getConnections()) { + DTNHost to = con.getOtherNode(getHost()); + if (m.getTo() == to) { + forTuples.add(new Tuple(m,con)); + } + } + } + + return forTuples; + } + + /** + * Tries to send messages for the connections that are mentioned + * in the Tuples in the order they are in the list until one of + * the connections starts transferring or all tuples have been tried. + * @param tuples The tuples to try + * @return The tuple whose connection accepted the message or null if + * none of the connections accepted the message that was meant for them. + */ + protected Tuple tryMessagesForConnected( + List> tuples) { + if (tuples.size() == 0) { + return null; + } + + for (Tuple t : tuples) { + Message m = t.getKey(); + Connection con = t.getValue(); + if (startTransfer(m, con) == RCV_OK) { + return t; + } + } + + return null; + } + + /** + * Goes trough the messages until the other node accepts one + * for receiving (or doesn't accept any). If a transfer is started, the + * connection is included in the list of sending connections. + * @param con Connection trough which the messages are sent + * @param messages A list of messages to try + * @return The message whose transfer was started or null if no + * transfer was started. + */ + protected Message tryAllMessages(Connection con, List messages) { + for (Message m : messages) { + int retVal = startTransfer(m, con); + if (retVal == RCV_OK) { + return m; // accepted a message, don't try others + } + else if (retVal > 0) { + return null; // should try later -> don't bother trying others + } + } + + return null; // no message was accepted + } + + /** + * Tries to send all given messages to all given connections. Connections + * are first iterated in the order they are in the list and for every + * connection, the messages are tried in the order they are in the list. + * Once an accepting connection is found, no other connections or messages + * are tried. + * @param messages The list of Messages to try + * @param connections The list of Connections to try + * @return The connections that started a transfer or null if no connection + * accepted a message. + */ + protected Connection tryMessagesToConnections(List messages, + List connections) { + for (int i=0, n=connections.size(); i connections = getConnections(); + if (connections.size() == 0 || this.getNrofMessages() == 0) { + return null; + } + + List messages = new ArrayList(this.getMessageCollection()); - this.sortByQueueMode(messages); - - return tryMessagesToConnections(messages, connections); - } - - /** - * Exchanges deliverable (to final recipient) messages between this host - * and all hosts this host is currently connected to. First all messages - * from this host are checked and then all other hosts are asked for - * messages to this host. If a transfer is started, the search ends. - * @return A connection that started a transfer or null if no transfer - * was started - */ - protected Connection exchangeDeliverableMessages() { + this.sortByQueueMode(messages); + + return tryMessagesToConnections(messages, connections); + } + + /** + * Exchanges deliverable (to final recipient) messages between this host + * and all hosts this host is currently connected to. First all messages + * from this host are checked and then all other hosts are asked for + * messages to this host. If a transfer is started, the search ends. + * @return A connection that started a transfer or null if no transfer + * was started + */ + protected Connection exchangeDeliverableMessages() { List connections = getConnections(); - - if (connections.size() == 0) { - return null; - } - - @SuppressWarnings(value = "unchecked") - Tuple t = - tryMessagesForConnected(sortByQueueMode(getMessagesForConnected())); - - if (t != null) { - return t.getValue(); // started transfer - } - - // didn't start transfer to any node -> ask messages from connected - for (Connection con : connections) { - if (con.getOtherNode(getHost()).requestDeliverableMessages(con)) { - return con; - } - } - - return null; - } - - - - /** - * Shuffles a messages list so the messages are in random order. - * @param messages The list to sort and shuffle - */ - protected void shuffleMessages(List messages) { - if (messages.size() <= 1) { - return; // nothing to shuffle - } - - Random rng = new Random(SimClock.getIntTime()); - Collections.shuffle(messages, rng); - } - - /** - * Adds a connections to sending connections which are monitored in - * the update. - * @see #update() - * @param con The connection to add - */ - protected void addToSendingConnections(Connection con) { - this.sendingConnections.add(con); - } - - /** - * Returns true if this router is transferring something at the moment or - * some transfer has not been finalized. - * @return true if this router is transferring something - */ - public boolean isTransferring() { - if (this.sendingConnections.size() > 0) { - return true; // sending something - } - + + if (connections.size() == 0) { + return null; + } + + @SuppressWarnings(value = "unchecked") + Tuple t = + tryMessagesForConnected(sortByQueueMode(getMessagesForConnected())); + + if (t != null) { + return t.getValue(); // started transfer + } + + // didn't start transfer to any node -> ask messages from connected + for (Connection con : connections) { + if (con.getOtherNode(getHost()).requestDeliverableMessages(con)) { + return con; + } + } + + return null; + } + + + + /** + * Shuffles a messages list so the messages are in random order. + * @param messages The list to sort and shuffle + */ + protected void shuffleMessages(List messages) { + if (messages.size() <= 1) { + return; // nothing to shuffle + } + + Random rng = new Random(SimClock.getIntTime()); + Collections.shuffle(messages, rng); + } + + /** + * Adds a connections to sending connections which are monitored in + * the update. + * @see #update() + * @param con The connection to add + */ + protected void addToSendingConnections(Connection con) { + this.sendingConnections.add(con); + } + + /** + * Returns true if this router is transferring something at the moment or + * some transfer has not been finalized. + * @return true if this router is transferring something + */ + public boolean isTransferring() { + if (this.sendingConnections.size() > 0) { + return true; // sending something + } + List connections = getConnections(); - - if (connections.size() == 0) { - return false; // not connected - } - - for (int i=0, n=connections.size(); imsgId. - * @param msgId The ID of the message - * @return True if the message is being sent false if not - */ - public boolean isSending(String msgId) { - for (Connection con : this.sendingConnections) { - if (con.getMessage() == null) { - continue; // transmission is finalized - } - if (con.getMessage().getId().equals(msgId)) { - return true; - } - } - return false; + + if (connections.size() == 0) { + return false; // not connected + } + + for (int i=0, n=connections.size(); imsgId. + * @param msgId The ID of the message + * @return True if the message is being sent false if not + */ + public boolean isSending(String msgId) { + for (Connection con : this.sendingConnections) { + if (con.getMessage() == null) { + continue; // transmission is finalized + } + if (con.getMessage().getId().equals(msgId)) { + return true; + } + } + return false; + } + /** * Returns true if the node has energy left (i.e., energy modeling is * enabled OR (is enabled and model has energy left)) @@ -569,24 +569,24 @@ public boolean isSending(String msgId) { */ public boolean hasEnergy() { return this.energy == null || this.energy.getEnergy() > 0; - } - - /** - * Checks out all sending connections to finalize the ready ones - * and abort those whose connection went down. Also drops messages - * whose TTL <= 0 (checking every one simulated minute). - * @see #addToSendingConnections(Connection) - */ - @Override - public void update() { + } + + /** + * Checks out all sending connections to finalize the ready ones + * and abort those whose connection went down. Also drops messages + * whose TTL <= 0 (checking every one simulated minute). + * @see #addToSendingConnections(Connection) + */ + @Override + public void update() { super.update(); - - /* in theory we can have multiple sending connections even though - currently all routers allow only one concurrent sending connection */ - for (int i=0; i= TTL_CHECK_INTERVAL && - sendingConnections.size() == 0) { - dropExpiredMessages(); - lastTtlCheck = SimClock.getTime(); - } - + } + + if (removeCurrent) { + // if the message being sent was holding excess buffer, free it + if (this.getFreeBufferSize() < 0) { + this.makeRoomForMessage(0); + } + sendingConnections.remove(i); + } + else { + /* index increase needed only if nothing was removed */ + i++; + } + } + + /* time to do a TTL check and drop old messages? Only if not sending */ + if (SimClock.getTime() - lastTtlCheck >= TTL_CHECK_INTERVAL && + sendingConnections.size() == 0) { + dropExpiredMessages(); + lastTtlCheck = SimClock.getTime(); + } + if (energy != null) { /* TODO: add support for other interfaces */ NetworkInterface iface = getHost().getInterface(1); energy.update(iface, getHost().getComBus()); - } - } - - /** - * Method is called just before a transfer is aborted at {@link #update()} - * due connection going down. This happens on the sending host. - * Subclasses that are interested of the event may want to override this. - * @param con The connection whose transfer was aborted - */ - protected void transferAborted(Connection con) { } - - /** - * Method is called just before a transfer is finalized - * at {@link #update()}. - * Subclasses that are interested of the event may want to override this. + } + } + + /** + * Method is called just before a transfer is aborted at {@link #update()} + * due connection going down. This happens on the sending host. + * Subclasses that are interested of the event may want to override this. + * @param con The connection whose transfer was aborted + */ + protected void transferAborted(Connection con) { } + + /** + * Method is called just before a transfer is finalized + * at {@link #update()}. + * Subclasses that are interested of the event may want to override this. * @param con The connection whose transfer was finalized - */ + */ protected void transferDone(Connection con) { } - + @Override public RoutingInfo getRoutingInfo() { RoutingInfo top = super.getRoutingInfo(); if (energy != null) { - top.addMoreInfo(new RoutingInfo("Energy level: " + + top.addMoreInfo(new RoutingInfo("Energy level: " + String.format("%.2f mAh", energy.getEnergy() / 3600))); } return top; - } - -} + } + +} diff --git a/routing/DirectDeliveryRouter.java b/routing/DirectDeliveryRouter.java index 2bfb107e7..271c85870 100644 --- a/routing/DirectDeliveryRouter.java +++ b/routing/DirectDeliveryRouter.java @@ -1,39 +1,39 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; - +package routing; + import core.Settings; - -/** - * Router that will deliver messages only to the final recipient. - */ -public class DirectDeliveryRouter extends ActiveRouter { - - public DirectDeliveryRouter(Settings s) { - super(s); - } - - protected DirectDeliveryRouter(DirectDeliveryRouter r) { - super(r); - } - - @Override - public void update() { - super.update(); - if (isTransferring() || !canStartTransfer()) { - return; // can't start a new transfer - } - - // Try only the messages that can be delivered to final recipient - if (exchangeDeliverableMessages() != null) { - return; // started a transfer - } - } - - @Override - public DirectDeliveryRouter replicate() { - return new DirectDeliveryRouter(this); - } -} + +/** + * Router that will deliver messages only to the final recipient. + */ +public class DirectDeliveryRouter extends ActiveRouter { + + public DirectDeliveryRouter(Settings s) { + super(s); + } + + protected DirectDeliveryRouter(DirectDeliveryRouter r) { + super(r); + } + + @Override + public void update() { + super.update(); + if (isTransferring() || !canStartTransfer()) { + return; // can't start a new transfer + } + + // Try only the messages that can be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; // started a transfer + } + } + + @Override + public DirectDeliveryRouter replicate() { + return new DirectDeliveryRouter(this); + } +} diff --git a/routing/EpidemicOracleRouter.java b/routing/EpidemicOracleRouter.java index 875f852d2..aa7c0fc4d 100644 --- a/routing/EpidemicOracleRouter.java +++ b/routing/EpidemicOracleRouter.java @@ -1,24 +1,24 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; - +package routing; + import java.util.ArrayList; import java.util.List; -import core.*; - +import core.*; + /** - *

+ *

* Epidemic message router with an oracle that tells when a message is delivered * and that message is then removed from all nodes that use this routing module. - * This router also ignores message size and all messages are delivered + * This router also ignores message size and all messages are delivered * immediately.

- * Note: This router module also bypasses ActiveRouter.update() - */ -public class EpidemicOracleRouter extends ActiveRouter { - + * Note: This router module also bypasses ActiveRouter.update() + */ +public class EpidemicOracleRouter extends ActiveRouter { + /** List of all routers in this node group */ private static List allRouters; @@ -26,33 +26,33 @@ public class EpidemicOracleRouter extends ActiveRouter { DTNSim.registerForReset(EpidemicOracleRouter.class.getCanonicalName()); reset(); } - - /** - * Constructor. Creates a new message router based on the settings in - * the given Settings object. - * @param s The settings object - */ - public EpidemicOracleRouter(Settings s) { - super(s); - } - - /** - * Copy constructor. - * @param r The router prototype where setting values are copied from - */ - protected EpidemicOracleRouter(EpidemicOracleRouter r) { + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public EpidemicOracleRouter(Settings s) { + super(s); + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected EpidemicOracleRouter(EpidemicOracleRouter r) { super(r); - allRouters.add(this); - } - + allRouters.add(this); + } + @Override public void changedConnection(Connection con) { super.changedConnection(con); - + if (con.isUp()) { DTNHost peer = con.getOtherNode(getHost()); List newMessages = new ArrayList(); - + for (Message m : peer.getMessageCollection()) { if (!this.hasMessage(m.getId())) { newMessages.add(m); @@ -69,26 +69,26 @@ public void changedConnection(Connection con) { private void sendMessageToConnected(Message m) { DTNHost host = getHost(); - + for (Connection c : getConnections()) { if (c.isReadyForTransfer() && c.startTransfer(host, m) == RCV_OK) { c.finalizeTransfer(); /* and finalize it right away */ - } + } } } - + public boolean createNewMessage(Message m) { boolean ok = super.createNewMessage(m); - + if (!ok) { throw new SimError("Can't create message " + m); } sendMessageToConnected(m); - + return true; } - + /** * Removes the message with the given ID from this router, if the router * has that message; otherwise does nothing. If the router was transferring @@ -103,10 +103,10 @@ public void removeDeliveredMessage(String id) { c.abortTransfer(); } } - this.deleteMessage(id, false); + this.deleteMessage(id, false); } } - + @Override public Message messageTransferred(String id, DTNHost from) { Message m = super.messageTransferred(id, from); @@ -120,62 +120,62 @@ public Message messageTransferred(String id, DTNHost from) { } else { sendMessageToConnected(m); } - + return m; } - + protected int checkReceiving(Message m) { - if ( isIncomingMessage(m.getId()) || hasMessage(m.getId()) || + if ( isIncomingMessage(m.getId()) || hasMessage(m.getId()) || isDeliveredMessage(m) ){ return DENIED_OLD; // already seen this message -> reject it } - + if (m.getTtl() <= 0 && m.getTo() != getHost()) { /* TTL has expired and this host is not the final recipient */ - return DENIED_TTL; + return DENIED_TTL; } /* remove oldest messages but not the ones being sent */ if (!makeRoomForMessage(m.getSize())) { return DENIED_NO_SPACE; // couldn't fit into buffer -> reject } - + return RCV_OK; } - + @Override protected void transferDone(Connection con) { Message m = con.getMessage(); - + if (m == null) { core.Debug.p("Null message for con " + con); return; } - + /* was the message delivered to the final recipient? */ - if (m.getTo() == con.getOtherNode(getHost())) { + if (m.getTo() == con.getOtherNode(getHost())) { this.deleteMessage(m.getId(), false); } } - - @Override - public void update() { + + @Override + public void update() { /* nothing to do; all transfers are started only when new connections are created or new messages are created or received, and transfers are finalized immediately */ - } - - - @Override - public EpidemicOracleRouter replicate() { - return new EpidemicOracleRouter(this); } - + + + @Override + public EpidemicOracleRouter replicate() { + return new EpidemicOracleRouter(this); + } + /** * Resets the static router list */ public static void reset() { allRouters = new ArrayList(); - } - -} \ No newline at end of file + } + +} diff --git a/routing/EpidemicRouter.java b/routing/EpidemicRouter.java index f2a696890..40e3fa858 100644 --- a/routing/EpidemicRouter.java +++ b/routing/EpidemicRouter.java @@ -1,56 +1,56 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; - +package routing; + import core.Settings; - -/** - * Epidemic message router with drop-oldest buffer and only single transferring - * connections at a time. - */ -public class EpidemicRouter extends ActiveRouter { - - /** - * Constructor. Creates a new message router based on the settings in - * the given Settings object. - * @param s The settings object - */ - public EpidemicRouter(Settings s) { - super(s); - //TODO: read&use epidemic router specific settings (if any) - } - - /** - * Copy constructor. - * @param r The router prototype where setting values are copied from - */ - protected EpidemicRouter(EpidemicRouter r) { - super(r); - //TODO: copy epidemic settings here (if any) - } - - @Override - public void update() { - super.update(); - if (isTransferring() || !canStartTransfer()) { - return; // transferring, don't try other connections yet - } - - // Try first the messages that can be delivered to final recipient - if (exchangeDeliverableMessages() != null) { - return; // started a transfer, don't try others (yet) - } - - // then try any/all message to any/all connection - this.tryAllMessagesToAllConnections(); - } - - - @Override - public EpidemicRouter replicate() { - return new EpidemicRouter(this); - } - -} \ No newline at end of file + +/** + * Epidemic message router with drop-oldest buffer and only single transferring + * connections at a time. + */ +public class EpidemicRouter extends ActiveRouter { + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public EpidemicRouter(Settings s) { + super(s); + //TODO: read&use epidemic router specific settings (if any) + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected EpidemicRouter(EpidemicRouter r) { + super(r); + //TODO: copy epidemic settings here (if any) + } + + @Override + public void update() { + super.update(); + if (isTransferring() || !canStartTransfer()) { + return; // transferring, don't try other connections yet + } + + // Try first the messages that can be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; // started a transfer, don't try others (yet) + } + + // then try any/all message to any/all connection + this.tryAllMessagesToAllConnections(); + } + + + @Override + public EpidemicRouter replicate() { + return new EpidemicRouter(this); + } + +} diff --git a/routing/FirstContactRouter.java b/routing/FirstContactRouter.java index f48fe7365..c0e316ece 100644 --- a/routing/FirstContactRouter.java +++ b/routing/FirstContactRouter.java @@ -1,74 +1,74 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; - +package routing; + import core.Connection; import core.DTNHost; import core.Message; import core.Settings; - -/** - * First contact router which uses only a single copy of the message - * (or fragments) and forwards it to the first available contact. - */ -public class FirstContactRouter extends ActiveRouter { - - /** - * Constructor. Creates a new message router based on the settings in - * the given Settings object. - * @param s The settings object - */ - public FirstContactRouter(Settings s) { - super(s); - } - - /** - * Copy constructor. - * @param r The router prototype where setting values are copied from - */ - protected FirstContactRouter(FirstContactRouter r) { - super(r); + +/** + * First contact router which uses only a single copy of the message + * (or fragments) and forwards it to the first available contact. + */ +public class FirstContactRouter extends ActiveRouter { + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public FirstContactRouter(Settings s) { + super(s); + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected FirstContactRouter(FirstContactRouter r) { + super(r); } - + @Override protected int checkReceiving(Message m, DTNHost from) { - int recvCheck = super.checkReceiving(m, from); - + int recvCheck = super.checkReceiving(m, from); + if (recvCheck == RCV_OK) { /* don't accept a message that has already traversed this node */ if (m.getHops().contains(getHost())) { recvCheck = DENIED_OLD; } } - + return recvCheck; - } - - @Override - public void update() { - super.update(); - if (isTransferring() || !canStartTransfer()) { - return; - } - - if (exchangeDeliverableMessages() != null) { - return; - } - - tryAllMessagesToAllConnections(); - } - + } + + @Override + public void update() { + super.update(); + if (isTransferring() || !canStartTransfer()) { + return; + } + + if (exchangeDeliverableMessages() != null) { + return; + } + + tryAllMessagesToAllConnections(); + } + @Override protected void transferDone(Connection con) { /* don't leave a copy for the sender */ this.deleteMessage(con.getMessage().getId(), false); } - - @Override - public FirstContactRouter replicate() { - return new FirstContactRouter(this); - } - -} \ No newline at end of file + + @Override + public FirstContactRouter replicate() { + return new FirstContactRouter(this); + } + +} diff --git a/routing/LifeRouter.java b/routing/LifeRouter.java index 8cb17a3d8..ae7ef5cb3 100644 --- a/routing/LifeRouter.java +++ b/routing/LifeRouter.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2011 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package routing; @@ -10,39 +10,39 @@ import core.Message; import core.Settings; import core.Connection; - -/** - * Router module mimicking the game-of-life behavior - */ + +/** + * Router module mimicking the game-of-life behavior + */ public class LifeRouter extends ActiveRouter { - - /** + + /** * Neighboring message count -setting id ({@value}). Two comma * separated values: min and max. Only if the amount of connected nodes * with the given message is between the min and max value, the message - * is accepted for transfer and kept in the buffer. + * is accepted for transfer and kept in the buffer. */ public static final String NM_COUNT_S = "nmcount"; private int countRange[]; - - /** - * Constructor. Creates a new message router based on the settings in - * the given Settings object. - * @param s The settings object - */ - public LifeRouter(Settings s) { + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public LifeRouter(Settings s) { super(s); - countRange = s.getCsvInts(NM_COUNT_S, 2); - } - - /** - * Copy constructor. - * @param r The router prototype where setting values are copied from - */ - protected LifeRouter(LifeRouter r) { + countRange = s.getCsvInts(NM_COUNT_S, 2); + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected LifeRouter(LifeRouter r) { super(r); - this.countRange = r.countRange; - } + this.countRange = r.countRange; + } /** * Counts how many of the connected peers have the given message @@ -53,63 +53,63 @@ private int getPeerMessageCount(Message m) { DTNHost me = getHost(); String id = m.getId(); int peerMsgCount = 0; - + for (Connection c : getConnections()) { if (c.getOtherNode(me).getRouter().hasMessage(id)) { peerMsgCount++; - } + } } - + return peerMsgCount; } - + @Override protected int checkReceiving(Message m, DTNHost from) { int peerMsgCount = getPeerMessageCount(m); - - if (peerMsgCount < this.countRange[0] || + + if (peerMsgCount < this.countRange[0] || peerMsgCount > this.countRange[1]) { return DENIED_POLICY; } - + /* peer message count check OK; receive based on other checks */ return super.checkReceiving(m, from); } - - @Override + + @Override public void update() { int peerMsgCount; - Vector messagesToDelete = new Vector(); + Vector messagesToDelete = new Vector(); super.update(); - - if (isTransferring() || !canStartTransfer()) { - return; /* transferring, don't try other connections yet */ - } - - /* Try first the messages that can be delivered to final recipient */ - if (exchangeDeliverableMessages() != null) { - return; - } + + if (isTransferring() || !canStartTransfer()) { + return; /* transferring, don't try other connections yet */ + } + + /* Try first the messages that can be delivered to final recipient */ + if (exchangeDeliverableMessages() != null) { + return; + } this.tryAllMessagesToAllConnections(); - + /* see if need to drop some messages... */ for (Message m : getMessageCollection()) { peerMsgCount = getPeerMessageCount(m); - if (peerMsgCount < this.countRange[0] || + if (peerMsgCount < this.countRange[0] || peerMsgCount > this.countRange[1]) { - messagesToDelete.add(m.getId()); + messagesToDelete.add(m.getId()); } - } + } for (String id : messagesToDelete) { /* ...and drop them */ this.deleteMessage(id, true); } - - } - - - @Override - public LifeRouter replicate() { - return new LifeRouter(this); - } - -} \ No newline at end of file + + } + + + @Override + public LifeRouter replicate() { + return new LifeRouter(this); + } + +} diff --git a/routing/MaxPropRouter.java b/routing/MaxPropRouter.java index c71d8a652..283e11b91 100644 --- a/routing/MaxPropRouter.java +++ b/routing/MaxPropRouter.java @@ -1,41 +1,41 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package routing; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import routing.maxprop.MaxPropDijkstra; -import routing.maxprop.MeetingProbabilitySet; -import routing.util.RoutingInfo; -import util.Tuple; -import core.Connection; -import core.DTNHost; -import core.Message; -import core.Settings; - -/** - * Implementation of MaxProp router as described in - * MaxProp: Routing for Vehicle-Based Disruption-Tolerant Networks by - * John Burgess et al. - * @version 1.0 - * - * Extension of the protocol by adding a parameter alpha (default 1) - * By new connection, the delivery likelihood is increased by alpha - * and divided by 1+alpha. Using the default results in the original - * algorithm. Refer to Karvo and Ott, Time Scales and Delay-Tolerant Routing - * Protocols Chants, 2008 - */ -public class MaxPropRouter extends ActiveRouter { + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import routing.maxprop.MaxPropDijkstra; +import routing.maxprop.MeetingProbabilitySet; +import routing.util.RoutingInfo; +import util.Tuple; +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; + +/** + * Implementation of MaxProp router as described in + * MaxProp: Routing for Vehicle-Based Disruption-Tolerant Networks by + * John Burgess et al. + * @version 1.0 + * + * Extension of the protocol by adding a parameter alpha (default 1) + * By new connection, the delivery likelihood is increased by alpha + * and divided by 1+alpha. Using the default results in the original + * algorithm. Refer to Karvo and Ott, Time Scales and Delay-Tolerant Routing + * Protocols Chants, 2008 + */ +public class MaxPropRouter extends ActiveRouter { /** Router's setting namespace ({@value})*/ public static final String MAXPROP_NS = "MaxPropRouter"; /** @@ -46,51 +46,51 @@ public class MaxPropRouter extends ActiveRouter { public static final int DEFAULT_PROB_SET_MAX_SIZE = 50; private static int probSetMaxSize; - /** probabilities of meeting hosts */ - private MeetingProbabilitySet probs; - /** meeting probabilities of all hosts from this host's point of view - * mapped using host's network address */ - private Map allProbs; - /** the cost-to-node calculator */ - private MaxPropDijkstra dijkstra; - /** IDs of the messages that are known to have reached the final dst */ - private Set ackedMessageIds; - /** mapping of the current costs for all messages. This should be set to - * null always when the costs should be updated (a host is met or a new - * message is received) */ - private Map costsForMessages; - /** From host of the last cost calculation */ - private DTNHost lastCostFrom; - - /** Map of which messages have been sent to which hosts from this host */ - private Map> sentMessages; - - /** Over how many samples the "average number of bytes transferred per - * transfer opportunity" is taken */ - public static int BYTES_TRANSFERRED_AVG_SAMPLES = 10; - private int[] avgSamples; - private int nextSampleIndex = 0; - /** current value for the "avg number of bytes transferred per transfer - * opportunity" */ - private int avgTransferredBytes = 0; - - /** The alpha parameter string*/ - public static final String ALPHA_S = "alpha"; - - /** The alpha variable, default = 1;*/ - private double alpha; - - /** The default value for alpha */ - public static final double DEFAULT_ALPHA = 1.0; - - /** - * Constructor. Creates a new prototype router based on the settings in - * the given Settings object. - * @param settings The settings object - */ - public MaxPropRouter(Settings settings) { - super(settings); - Settings maxPropSettings = new Settings(MAXPROP_NS); + /** probabilities of meeting hosts */ + private MeetingProbabilitySet probs; + /** meeting probabilities of all hosts from this host's point of view + * mapped using host's network address */ + private Map allProbs; + /** the cost-to-node calculator */ + private MaxPropDijkstra dijkstra; + /** IDs of the messages that are known to have reached the final dst */ + private Set ackedMessageIds; + /** mapping of the current costs for all messages. This should be set to + * null always when the costs should be updated (a host is met or a new + * message is received) */ + private Map costsForMessages; + /** From host of the last cost calculation */ + private DTNHost lastCostFrom; + + /** Map of which messages have been sent to which hosts from this host */ + private Map> sentMessages; + + /** Over how many samples the "average number of bytes transferred per + * transfer opportunity" is taken */ + public static int BYTES_TRANSFERRED_AVG_SAMPLES = 10; + private int[] avgSamples; + private int nextSampleIndex = 0; + /** current value for the "avg number of bytes transferred per transfer + * opportunity" */ + private int avgTransferredBytes = 0; + + /** The alpha parameter string*/ + public static final String ALPHA_S = "alpha"; + + /** The alpha variable, default = 1;*/ + private double alpha; + + /** The default value for alpha */ + public static final double DEFAULT_ALPHA = 1.0; + + /** + * Constructor. Creates a new prototype router based on the settings in + * the given Settings object. + * @param settings The settings object + */ + public MaxPropRouter(Settings settings) { + super(settings); + Settings maxPropSettings = new Settings(MAXPROP_NS); if (maxPropSettings.contains(ALPHA_S)) { alpha = maxPropSettings.getDouble(ALPHA_S); } else { @@ -103,498 +103,498 @@ public MaxPropRouter(Settings settings) { } else { probSetMaxSize = DEFAULT_PROB_SET_MAX_SIZE; } - } - - /** - * Copy constructor. Creates a new router based on the given prototype. - * @param r The router prototype where setting values are copied from - */ - protected MaxPropRouter(MaxPropRouter r) { - super(r); + } + + /** + * Copy constructor. Creates a new router based on the given prototype. + * @param r The router prototype where setting values are copied from + */ + protected MaxPropRouter(MaxPropRouter r) { + super(r); this.alpha = r.alpha; this.probs = new MeetingProbabilitySet(probSetMaxSize, this.alpha); - this.allProbs = new HashMap(); - this.dijkstra = new MaxPropDijkstra(this.allProbs); - this.ackedMessageIds = new HashSet(); - this.avgSamples = new int[BYTES_TRANSFERRED_AVG_SAMPLES]; - this.sentMessages = new HashMap>(); - } - - @Override - public void changedConnection(Connection con) { - super.changedConnection(con); - - if (con.isUp()) { // new connection - this.costsForMessages = null; // invalidate old cost estimates - - if (con.isInitiator(getHost())) { - /* initiator performs all the actions on behalf of the - * other node too (so that the meeting probs are updated - * for both before exchanging them) */ - DTNHost otherHost = con.getOtherNode(getHost()); - MessageRouter mRouter = otherHost.getRouter(); - - assert mRouter instanceof MaxPropRouter : "MaxProp only works "+ - " with other routers of same type"; - MaxPropRouter otherRouter = (MaxPropRouter)mRouter; - - /* exchange ACKed message data */ - this.ackedMessageIds.addAll(otherRouter.ackedMessageIds); - otherRouter.ackedMessageIds.addAll(this.ackedMessageIds); - deleteAckedMessages(); - otherRouter.deleteAckedMessages(); - - /* update both meeting probabilities */ - probs.updateMeetingProbFor(otherHost.getAddress()); - otherRouter.probs.updateMeetingProbFor(getHost().getAddress()); - - /* exchange the transitive probabilities */ - this.updateTransitiveProbs(otherRouter.allProbs); - otherRouter.updateTransitiveProbs(this.allProbs); - this.allProbs.put(otherHost.getAddress(), - otherRouter.probs.replicate()); - otherRouter.allProbs.put(getHost().getAddress(), - this.probs.replicate()); - } - } - else { - /* connection went down, update transferred bytes average */ - updateTransferredBytesAvg(con.getTotalBytesTransferred()); - } - } - - /** - * Updates transitive probability values by replacing the current - * MeetingProbabilitySets with the values from the given mapping - * if the given sets have more recent updates. - * @param p Mapping of the values of the other host - */ - private void updateTransitiveProbs(Map p) { - for (Map.Entry e : p.entrySet()) { - MeetingProbabilitySet myMps = this.allProbs.get(e.getKey()); - if (myMps == null || - e.getValue().getLastUpdateTime() > myMps.getLastUpdateTime() ) { - this.allProbs.put(e.getKey(), e.getValue().replicate()); - } - } - } - - /** - * Deletes the messages from the message buffer that are known to be ACKed - */ - private void deleteAckedMessages() { - for (String id : this.ackedMessageIds) { - if (this.hasMessage(id) && !isSending(id)) { - this.deleteMessage(id, false); - } - } - } - - @Override - public Message messageTransferred(String id, DTNHost from) { - this.costsForMessages = null; // new message -> invalidate costs - Message m = super.messageTransferred(id, from); - /* was this node the final recipient of the message? */ - if (isDeliveredMessage(m)) { - this.ackedMessageIds.add(id); - } - return m; - } - - /** - * Method is called just before a transfer is finalized - * at {@link ActiveRouter#update()}. MaxProp makes book keeping of the - * delivered messages so their IDs are stored. - * @param con The connection whose transfer was finalized - */ - @Override - protected void transferDone(Connection con) { - Message m = con.getMessage(); - String id = m.getId(); - DTNHost recipient = con.getOtherNode(getHost()); - Set sentMsgIds = this.sentMessages.get(recipient); - - /* was the message delivered to the final recipient? */ - if (m.getTo() == recipient) { - this.ackedMessageIds.add(m.getId()); // yes, add to ACKed messages - this.deleteMessage(m.getId(), false); // delete from buffer - } - - /* update the map of where each message is already sent */ - if (sentMsgIds == null) { - sentMsgIds = new HashSet(); - this.sentMessages.put(recipient, sentMsgIds); - } - sentMsgIds.add(id); - } - - /** - * Updates the average estimate of the number of bytes transferred per - * transfer opportunity. - * @param newValue The new value to add to the estimate - */ - private void updateTransferredBytesAvg(int newValue) { - int realCount = 0; - int sum = 0; - - this.avgSamples[this.nextSampleIndex++] = newValue; - if(this.nextSampleIndex >= BYTES_TRANSFERRED_AVG_SAMPLES) { - this.nextSampleIndex = 0; - } - - for (int i=0; i < BYTES_TRANSFERRED_AVG_SAMPLES; i++) { - if (this.avgSamples[i] > 0) { // only values above zero count - realCount++; - sum += this.avgSamples[i]; - } - } - - if (realCount > 0) { - this.avgTransferredBytes = sum / realCount; - } - else { // no samples or all samples are zero - this.avgTransferredBytes = 0; - } - } - - /** - * Returns the next message that should be dropped, according to MaxProp's - * message ordering scheme (see {@link MaxPropTupleComparator}). - * @param excludeMsgBeingSent If true, excludes message(s) that are - * being sent from the next-to-be-dropped check (i.e., if next message to - * drop is being sent, the following message is returned) - * @return The oldest message or null if no message could be returned - * (no messages in buffer or all messages in buffer are being sent and - * exludeMsgBeingSent is true) - */ + this.allProbs = new HashMap(); + this.dijkstra = new MaxPropDijkstra(this.allProbs); + this.ackedMessageIds = new HashSet(); + this.avgSamples = new int[BYTES_TRANSFERRED_AVG_SAMPLES]; + this.sentMessages = new HashMap>(); + } + + @Override + public void changedConnection(Connection con) { + super.changedConnection(con); + + if (con.isUp()) { // new connection + this.costsForMessages = null; // invalidate old cost estimates + + if (con.isInitiator(getHost())) { + /* initiator performs all the actions on behalf of the + * other node too (so that the meeting probs are updated + * for both before exchanging them) */ + DTNHost otherHost = con.getOtherNode(getHost()); + MessageRouter mRouter = otherHost.getRouter(); + + assert mRouter instanceof MaxPropRouter : "MaxProp only works "+ + " with other routers of same type"; + MaxPropRouter otherRouter = (MaxPropRouter)mRouter; + + /* exchange ACKed message data */ + this.ackedMessageIds.addAll(otherRouter.ackedMessageIds); + otherRouter.ackedMessageIds.addAll(this.ackedMessageIds); + deleteAckedMessages(); + otherRouter.deleteAckedMessages(); + + /* update both meeting probabilities */ + probs.updateMeetingProbFor(otherHost.getAddress()); + otherRouter.probs.updateMeetingProbFor(getHost().getAddress()); + + /* exchange the transitive probabilities */ + this.updateTransitiveProbs(otherRouter.allProbs); + otherRouter.updateTransitiveProbs(this.allProbs); + this.allProbs.put(otherHost.getAddress(), + otherRouter.probs.replicate()); + otherRouter.allProbs.put(getHost().getAddress(), + this.probs.replicate()); + } + } + else { + /* connection went down, update transferred bytes average */ + updateTransferredBytesAvg(con.getTotalBytesTransferred()); + } + } + + /** + * Updates transitive probability values by replacing the current + * MeetingProbabilitySets with the values from the given mapping + * if the given sets have more recent updates. + * @param p Mapping of the values of the other host + */ + private void updateTransitiveProbs(Map p) { + for (Map.Entry e : p.entrySet()) { + MeetingProbabilitySet myMps = this.allProbs.get(e.getKey()); + if (myMps == null || + e.getValue().getLastUpdateTime() > myMps.getLastUpdateTime() ) { + this.allProbs.put(e.getKey(), e.getValue().replicate()); + } + } + } + + /** + * Deletes the messages from the message buffer that are known to be ACKed + */ + private void deleteAckedMessages() { + for (String id : this.ackedMessageIds) { + if (this.hasMessage(id) && !isSending(id)) { + this.deleteMessage(id, false); + } + } + } + + @Override + public Message messageTransferred(String id, DTNHost from) { + this.costsForMessages = null; // new message -> invalidate costs + Message m = super.messageTransferred(id, from); + /* was this node the final recipient of the message? */ + if (isDeliveredMessage(m)) { + this.ackedMessageIds.add(id); + } + return m; + } + + /** + * Method is called just before a transfer is finalized + * at {@link ActiveRouter#update()}. MaxProp makes book keeping of the + * delivered messages so their IDs are stored. + * @param con The connection whose transfer was finalized + */ + @Override + protected void transferDone(Connection con) { + Message m = con.getMessage(); + String id = m.getId(); + DTNHost recipient = con.getOtherNode(getHost()); + Set sentMsgIds = this.sentMessages.get(recipient); + + /* was the message delivered to the final recipient? */ + if (m.getTo() == recipient) { + this.ackedMessageIds.add(m.getId()); // yes, add to ACKed messages + this.deleteMessage(m.getId(), false); // delete from buffer + } + + /* update the map of where each message is already sent */ + if (sentMsgIds == null) { + sentMsgIds = new HashSet(); + this.sentMessages.put(recipient, sentMsgIds); + } + sentMsgIds.add(id); + } + + /** + * Updates the average estimate of the number of bytes transferred per + * transfer opportunity. + * @param newValue The new value to add to the estimate + */ + private void updateTransferredBytesAvg(int newValue) { + int realCount = 0; + int sum = 0; + + this.avgSamples[this.nextSampleIndex++] = newValue; + if(this.nextSampleIndex >= BYTES_TRANSFERRED_AVG_SAMPLES) { + this.nextSampleIndex = 0; + } + + for (int i=0; i < BYTES_TRANSFERRED_AVG_SAMPLES; i++) { + if (this.avgSamples[i] > 0) { // only values above zero count + realCount++; + sum += this.avgSamples[i]; + } + } + + if (realCount > 0) { + this.avgTransferredBytes = sum / realCount; + } + else { // no samples or all samples are zero + this.avgTransferredBytes = 0; + } + } + + /** + * Returns the next message that should be dropped, according to MaxProp's + * message ordering scheme (see {@link MaxPropTupleComparator}). + * @param excludeMsgBeingSent If true, excludes message(s) that are + * being sent from the next-to-be-dropped check (i.e., if next message to + * drop is being sent, the following message is returned) + * @return The oldest message or null if no message could be returned + * (no messages in buffer or all messages in buffer are being sent and + * exludeMsgBeingSent is true) + */ @Override - protected Message getNextMessageToRemove(boolean excludeMsgBeingSent) { - Collection messages = this.getMessageCollection(); - List validMessages = new ArrayList(); - - for (Message m : messages) { - if (excludeMsgBeingSent && isSending(m.getId())) { - continue; // skip the message(s) that router is sending - } - validMessages.add(m); - } - - Collections.sort(validMessages, - new MaxPropComparator(this.calcThreshold())); - - return validMessages.get(validMessages.size()-1); // return last message - } - - @Override - public void update() { - super.update(); - if (!canStartTransfer() ||isTransferring()) { - return; // nothing to transfer or is currently transferring - } - - // try messages that could be delivered to final recipient - if (exchangeDeliverableMessages() != null) { - return; - } - - tryOtherMessages(); - } - - /** - * Returns the message delivery cost between two hosts from this host's - * point of view. If there is no path between "from" and "to" host, - * Double.MAX_VALUE is returned. Paths are calculated only to hosts - * that this host has messages to. - * @param from The host where a message is coming from - * @param to The host where a message would be destined to - * @return The cost of the cheapest path to the destination or - * Double.MAX_VALUE if such a path doesn't exist - */ - public double getCost(DTNHost from, DTNHost to) { - /* check if the cached values are OK */ - if (this.costsForMessages == null || lastCostFrom != from) { - /* cached costs are invalid -> calculate new costs */ - this.allProbs.put(getHost().getAddress(), this.probs); - int fromIndex = from.getAddress(); - - /* calculate paths only to nodes we have messages to - * (optimization) */ - Set toSet = new HashSet(); - for (Message m : getMessageCollection()) { - toSet.add(m.getTo().getAddress()); - } - - this.costsForMessages = dijkstra.getCosts(fromIndex, toSet); - this.lastCostFrom = from; // store source host for caching checks - } - - if (costsForMessages.containsKey(to.getAddress())) { - return costsForMessages.get(to.getAddress()); - } - else { - /* there's no known path to the given host */ - return Double.MAX_VALUE; - } - } - - /** - * Tries to send all other messages to all connected hosts ordered by - * hop counts and their delivery probability - * @return The return value of {@link #tryMessagesForConnected(List)} - */ - private Tuple tryOtherMessages() { - List> messages = - new ArrayList>(); - - Collection msgCollection = getMessageCollection(); - - /* for all connected hosts that are not transferring at the moment, - * collect all the messages that could be sent */ - for (Connection con : getConnections()) { - DTNHost other = con.getOtherNode(getHost()); - MaxPropRouter othRouter = (MaxPropRouter)other.getRouter(); - Set sentMsgIds = this.sentMessages.get(other); - - if (othRouter.isTransferring()) { - continue; // skip hosts that are transferring - } - - for (Message m : msgCollection) { - /* skip messages that the other host has or that have - * passed the other host */ - if (othRouter.hasMessage(m.getId()) || - m.getHops().contains(other)) { - continue; - } - /* skip message if this host has already sent it to the other - host (regardless of if the other host still has it) */ - if (sentMsgIds != null && sentMsgIds.contains(m.getId())) { - continue; - } - /* message was a good candidate for sending */ - messages.add(new Tuple(m,con)); - } - } - - if (messages.size() == 0) { - return null; - } - - /* sort the message-connection tuples according to the criteria - * defined in MaxPropTupleComparator */ - Collections.sort(messages, new MaxPropTupleComparator(calcThreshold())); - return tryMessagesForConnected(messages); - } - - /** - * Calculates and returns the current threshold value for the buffer's split - * based on the average number of bytes transferred per transfer opportunity - * and the hop counts of the messages in the buffer. Method is public only - * to make testing easier. - * @return current threshold value (hop count) for the buffer's split - */ - public int calcThreshold() { - /* b, x and p refer to respective variables in the paper's equations */ - int b = this.getBufferSize(); - int x = this.avgTransferredBytes; - int p; - - if (x == 0) { - /* can't calc the threshold because there's no transfer data */ - return 0; - } - - /* calculates the portion (bytes) of the buffer selected for priority */ - if (x < b/2) { - p = x; - } - else if (b/2 <= x && x < b) { - p = Math.min(x, b-x); - } - else { - return 0; // no need for the threshold - } - - /* creates a copy of the messages list, sorted by hop count */ - ArrayList msgs = new ArrayList(); - msgs.addAll(getMessageCollection()); - if (msgs.size() == 0) { - return 0; // no messages -> no need for threshold - } - /* anonymous comparator class for hop count comparison */ - Comparator hopCountComparator = new Comparator() { - public int compare(Message m1, Message m2) { - return m1.getHopCount() - m2.getHopCount(); - } - }; - Collections.sort(msgs, hopCountComparator); - - /* finds the first message that is beyond the calculated portion */ - int i=0; - for (int n=msgs.size(); i0; i++) { - p -= msgs.get(i).getSize(); - } - - i--; // the last round moved i one index too far + protected Message getNextMessageToRemove(boolean excludeMsgBeingSent) { + Collection messages = this.getMessageCollection(); + List validMessages = new ArrayList(); + + for (Message m : messages) { + if (excludeMsgBeingSent && isSending(m.getId())) { + continue; // skip the message(s) that router is sending + } + validMessages.add(m); + } + + Collections.sort(validMessages, + new MaxPropComparator(this.calcThreshold())); + + return validMessages.get(validMessages.size()-1); // return last message + } + + @Override + public void update() { + super.update(); + if (!canStartTransfer() ||isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + // try messages that could be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; + } + + tryOtherMessages(); + } + + /** + * Returns the message delivery cost between two hosts from this host's + * point of view. If there is no path between "from" and "to" host, + * Double.MAX_VALUE is returned. Paths are calculated only to hosts + * that this host has messages to. + * @param from The host where a message is coming from + * @param to The host where a message would be destined to + * @return The cost of the cheapest path to the destination or + * Double.MAX_VALUE if such a path doesn't exist + */ + public double getCost(DTNHost from, DTNHost to) { + /* check if the cached values are OK */ + if (this.costsForMessages == null || lastCostFrom != from) { + /* cached costs are invalid -> calculate new costs */ + this.allProbs.put(getHost().getAddress(), this.probs); + int fromIndex = from.getAddress(); + + /* calculate paths only to nodes we have messages to + * (optimization) */ + Set toSet = new HashSet(); + for (Message m : getMessageCollection()) { + toSet.add(m.getTo().getAddress()); + } + + this.costsForMessages = dijkstra.getCosts(fromIndex, toSet); + this.lastCostFrom = from; // store source host for caching checks + } + + if (costsForMessages.containsKey(to.getAddress())) { + return costsForMessages.get(to.getAddress()); + } + else { + /* there's no known path to the given host */ + return Double.MAX_VALUE; + } + } + + /** + * Tries to send all other messages to all connected hosts ordered by + * hop counts and their delivery probability + * @return The return value of {@link #tryMessagesForConnected(List)} + */ + private Tuple tryOtherMessages() { + List> messages = + new ArrayList>(); + + Collection msgCollection = getMessageCollection(); + + /* for all connected hosts that are not transferring at the moment, + * collect all the messages that could be sent */ + for (Connection con : getConnections()) { + DTNHost other = con.getOtherNode(getHost()); + MaxPropRouter othRouter = (MaxPropRouter)other.getRouter(); + Set sentMsgIds = this.sentMessages.get(other); + + if (othRouter.isTransferring()) { + continue; // skip hosts that are transferring + } + + for (Message m : msgCollection) { + /* skip messages that the other host has or that have + * passed the other host */ + if (othRouter.hasMessage(m.getId()) || + m.getHops().contains(other)) { + continue; + } + /* skip message if this host has already sent it to the other + host (regardless of if the other host still has it) */ + if (sentMsgIds != null && sentMsgIds.contains(m.getId())) { + continue; + } + /* message was a good candidate for sending */ + messages.add(new Tuple(m,con)); + } + } + + if (messages.size() == 0) { + return null; + } + + /* sort the message-connection tuples according to the criteria + * defined in MaxPropTupleComparator */ + Collections.sort(messages, new MaxPropTupleComparator(calcThreshold())); + return tryMessagesForConnected(messages); + } + + /** + * Calculates and returns the current threshold value for the buffer's split + * based on the average number of bytes transferred per transfer opportunity + * and the hop counts of the messages in the buffer. Method is public only + * to make testing easier. + * @return current threshold value (hop count) for the buffer's split + */ + public int calcThreshold() { + /* b, x and p refer to respective variables in the paper's equations */ + int b = this.getBufferSize(); + int x = this.avgTransferredBytes; + int p; + + if (x == 0) { + /* can't calc the threshold because there's no transfer data */ + return 0; + } + + /* calculates the portion (bytes) of the buffer selected for priority */ + if (x < b/2) { + p = x; + } + else if (b/2 <= x && x < b) { + p = Math.min(x, b-x); + } + else { + return 0; // no need for the threshold + } + + /* creates a copy of the messages list, sorted by hop count */ + ArrayList msgs = new ArrayList(); + msgs.addAll(getMessageCollection()); + if (msgs.size() == 0) { + return 0; // no messages -> no need for threshold + } + /* anonymous comparator class for hop count comparison */ + Comparator hopCountComparator = new Comparator() { + public int compare(Message m1, Message m2) { + return m1.getHopCount() - m2.getHopCount(); + } + }; + Collections.sort(msgs, hopCountComparator); + + /* finds the first message that is beyond the calculated portion */ + int i=0; + for (int n=msgs.size(); i0; i++) { + p -= msgs.get(i).getSize(); + } + + i--; // the last round moved i one index too far if (i < 0) { return 0; } - - /* now i points to the first packet that exceeds portion p; - * the threshold is that packet's hop count + 1 (so that packet and - * perhaps some more are included in the priority part) */ - return msgs.get(i).getHopCount() + 1; - } - - /** - * Message comparator for the MaxProp routing module. - * Messages that have a hop count smaller than the given - * threshold are given priority and they are ordered by their hop count. - * Other messages are ordered by their delivery cost. - */ - private class MaxPropComparator implements Comparator { - private int threshold; - private DTNHost from1; - private DTNHost from2; - - /** - * Constructor. Assumes that the host where all the costs are calculated - * from is this router's host. - * @param treshold Messages with the hop count smaller than this - * value are transferred first (and ordered by the hop count) - */ - public MaxPropComparator(int treshold) { - this.threshold = treshold; - this.from1 = this.from2 = getHost(); - } - - /** - * Constructor. - * @param treshold Messages with the hop count smaller than this - * value are transferred first (and ordered by the hop count) - * @param from1 The host where the cost of msg1 is calculated from - * @param from2 The host where the cost of msg2 is calculated from - */ - public MaxPropComparator(int treshold, DTNHost from1, DTNHost from2) { - this.threshold = treshold; - this.from1 = from1; - this.from2 = from2; - } - - /** - * Compares two messages and returns -1 if the first given message - * should be first in order, 1 if the second message should be first - * or 0 if message order can't be decided. If both messages' hop count - * is less than the threshold, messages are compared by their hop count - * (smaller is first). If only other's hop count is below the threshold, - * that comes first. If both messages are below the threshold, the one - * with smaller cost (determined by - * {@link MaxPropRouter#getCost(DTNHost, DTNHost)}) is first. - */ - public int compare(Message msg1, Message msg2) { - double p1, p2; - int hopc1 = msg1.getHopCount(); - int hopc2 = msg2.getHopCount(); - - if (msg1 == msg2) { - return 0; - } - - /* if one message's hop count is above and the other one's below the - * threshold, the one below should be sent first */ - if (hopc1 < threshold && hopc2 >= threshold) { - return -1; // message1 should be first - } - else if (hopc2 < threshold && hopc1 >= threshold) { - return 1; // message2 -"- - } - - /* if both are below the threshold, one with lower hop count should - * be sent first */ - if (hopc1 < threshold && hopc2 < threshold) { - return hopc1 - hopc2; - } - - /* both messages have more than threshold hops -> cost of the - * message path is used for ordering */ - p1 = getCost(from1, msg1.getTo()); - p2 = getCost(from2, msg2.getTo()); - - /* the one with lower cost should be sent first */ - if (p1-p2 == 0) { - /* if costs are equal, hop count breaks ties. If even hop counts - are equal, the queue ordering is used */ - if (hopc1 == hopc2) { - return compareByQueueMode(msg1, msg2); - } - else { - return hopc1 - hopc2; - } - } - else if (p1-p2 < 0) { - return -1; // msg1 had the smaller cost - } - else { - return 1; // msg2 had the smaller cost - } - } - } - - /** - * Message-Connection tuple comparator for the MaxProp routing - * module. Uses {@link MaxPropComparator} on the messages of the tuples - * setting the "from" host for that message to be the one in the connection - * tuple (i.e., path is calculated starting from the host on the other end - * of the connection). - */ - private class MaxPropTupleComparator - implements Comparator > { - private int threshold; - - public MaxPropTupleComparator(int threshold) { - this.threshold = threshold; - } - - /** - * Compares two message-connection tuples using the - * {@link MaxPropComparator#compare(Message, Message)}. - */ - public int compare(Tuple tuple1, - Tuple tuple2) { - MaxPropComparator comp; - DTNHost from1 = tuple1.getValue().getOtherNode(getHost()); - DTNHost from2 = tuple2.getValue().getOtherNode(getHost()); - - comp = new MaxPropComparator(threshold, from1, from2); - return comp.compare(tuple1.getKey(), tuple2.getKey()); - } - } - - - @Override - public RoutingInfo getRoutingInfo() { - RoutingInfo top = super.getRoutingInfo(); - RoutingInfo ri = new RoutingInfo(probs.getAllProbs().size() + - " meeting probabilities"); - - /* show meeting probabilities for this host */ - for (Map.Entry e : probs.getAllProbs().entrySet()) { - Integer host = e.getKey(); - Double value = e.getValue(); - ri.addMoreInfo(new RoutingInfo(String.format("host %d : %.6f", - host, value))); - } - - top.addMoreInfo(ri); - top.addMoreInfo(new RoutingInfo("Avg transferred bytes: " + - this.avgTransferredBytes)); - - return top; - } - - @Override - public MessageRouter replicate() { - MaxPropRouter r = new MaxPropRouter(this); - return r; - } -} \ No newline at end of file + + /* now i points to the first packet that exceeds portion p; + * the threshold is that packet's hop count + 1 (so that packet and + * perhaps some more are included in the priority part) */ + return msgs.get(i).getHopCount() + 1; + } + + /** + * Message comparator for the MaxProp routing module. + * Messages that have a hop count smaller than the given + * threshold are given priority and they are ordered by their hop count. + * Other messages are ordered by their delivery cost. + */ + private class MaxPropComparator implements Comparator { + private int threshold; + private DTNHost from1; + private DTNHost from2; + + /** + * Constructor. Assumes that the host where all the costs are calculated + * from is this router's host. + * @param treshold Messages with the hop count smaller than this + * value are transferred first (and ordered by the hop count) + */ + public MaxPropComparator(int treshold) { + this.threshold = treshold; + this.from1 = this.from2 = getHost(); + } + + /** + * Constructor. + * @param treshold Messages with the hop count smaller than this + * value are transferred first (and ordered by the hop count) + * @param from1 The host where the cost of msg1 is calculated from + * @param from2 The host where the cost of msg2 is calculated from + */ + public MaxPropComparator(int treshold, DTNHost from1, DTNHost from2) { + this.threshold = treshold; + this.from1 = from1; + this.from2 = from2; + } + + /** + * Compares two messages and returns -1 if the first given message + * should be first in order, 1 if the second message should be first + * or 0 if message order can't be decided. If both messages' hop count + * is less than the threshold, messages are compared by their hop count + * (smaller is first). If only other's hop count is below the threshold, + * that comes first. If both messages are below the threshold, the one + * with smaller cost (determined by + * {@link MaxPropRouter#getCost(DTNHost, DTNHost)}) is first. + */ + public int compare(Message msg1, Message msg2) { + double p1, p2; + int hopc1 = msg1.getHopCount(); + int hopc2 = msg2.getHopCount(); + + if (msg1 == msg2) { + return 0; + } + + /* if one message's hop count is above and the other one's below the + * threshold, the one below should be sent first */ + if (hopc1 < threshold && hopc2 >= threshold) { + return -1; // message1 should be first + } + else if (hopc2 < threshold && hopc1 >= threshold) { + return 1; // message2 -"- + } + + /* if both are below the threshold, one with lower hop count should + * be sent first */ + if (hopc1 < threshold && hopc2 < threshold) { + return hopc1 - hopc2; + } + + /* both messages have more than threshold hops -> cost of the + * message path is used for ordering */ + p1 = getCost(from1, msg1.getTo()); + p2 = getCost(from2, msg2.getTo()); + + /* the one with lower cost should be sent first */ + if (p1-p2 == 0) { + /* if costs are equal, hop count breaks ties. If even hop counts + are equal, the queue ordering is used */ + if (hopc1 == hopc2) { + return compareByQueueMode(msg1, msg2); + } + else { + return hopc1 - hopc2; + } + } + else if (p1-p2 < 0) { + return -1; // msg1 had the smaller cost + } + else { + return 1; // msg2 had the smaller cost + } + } + } + + /** + * Message-Connection tuple comparator for the MaxProp routing + * module. Uses {@link MaxPropComparator} on the messages of the tuples + * setting the "from" host for that message to be the one in the connection + * tuple (i.e., path is calculated starting from the host on the other end + * of the connection). + */ + private class MaxPropTupleComparator + implements Comparator > { + private int threshold; + + public MaxPropTupleComparator(int threshold) { + this.threshold = threshold; + } + + /** + * Compares two message-connection tuples using the + * {@link MaxPropComparator#compare(Message, Message)}. + */ + public int compare(Tuple tuple1, + Tuple tuple2) { + MaxPropComparator comp; + DTNHost from1 = tuple1.getValue().getOtherNode(getHost()); + DTNHost from2 = tuple2.getValue().getOtherNode(getHost()); + + comp = new MaxPropComparator(threshold, from1, from2); + return comp.compare(tuple1.getKey(), tuple2.getKey()); + } + } + + + @Override + public RoutingInfo getRoutingInfo() { + RoutingInfo top = super.getRoutingInfo(); + RoutingInfo ri = new RoutingInfo(probs.getAllProbs().size() + + " meeting probabilities"); + + /* show meeting probabilities for this host */ + for (Map.Entry e : probs.getAllProbs().entrySet()) { + Integer host = e.getKey(); + Double value = e.getValue(); + ri.addMoreInfo(new RoutingInfo(String.format("host %d : %.6f", + host, value))); + } + + top.addMoreInfo(ri); + top.addMoreInfo(new RoutingInfo("Avg transferred bytes: " + + this.avgTransferredBytes)); + + return top; + } + + @Override + public MessageRouter replicate() { + MaxPropRouter r = new MaxPropRouter(this); + return r; + } +} diff --git a/routing/MaxPropRouterWithEstimation.java b/routing/MaxPropRouterWithEstimation.java index 8f5094bf2..6a7370a55 100644 --- a/routing/MaxPropRouterWithEstimation.java +++ b/routing/MaxPropRouterWithEstimation.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; - +package routing; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -23,34 +23,34 @@ import core.Message; import core.Settings; import core.SimClock; - -/** - * Implementation of MaxProp router as described in - * MaxProp: Routing for Vehicle-Based Disruption-Tolerant Networks by + +/** + * Implementation of MaxProp router as described in + * MaxProp: Routing for Vehicle-Based Disruption-Tolerant Networks by * John Burgess et al. - * + * * but with parameter estimation for finding an alpha based on timescale * definition: - * + * * Extension of the protocol by adding a parameter alpha (default 1) * By new connection, the delivery likelihood is increased by alpha - * and divided by 1+alpha. Using the default results in the original - * algorithm. Refer to Karvo and Ott, Time Scales and Delay-Tolerant Routing - * Protocols Chants, 2008 - * + * and divided by 1+alpha. Using the default results in the original + * algorithm. Refer to Karvo and Ott, Time Scales and Delay-Tolerant Routing + * Protocols Chants, 2008 + * * This version tries to estimate a good value of alpha from a timescale parameter * given by the user, and from the encounters the node sees during simulation. - * - * @version 1.0 - */ + * + * @version 1.0 + */ public class MaxPropRouterWithEstimation extends ActiveRouter { - /** probabilities of meeting hosts */ + /** probabilities of meeting hosts */ private MeetingProbabilitySet probs; - /** meeting probabilities of all hosts from this host's point of view + /** meeting probabilities of all hosts from this host's point of view * mapped using host's network address */ private Map allProbs; /** the cost-to-node calculator */ - private MaxPropDijkstra dijkstra; + private MaxPropDijkstra dijkstra; /** IDs of the messages that are known to have reached the final dst */ private Set ackedMessageIds; /** mapping of the current costs for all messages. This should be set to @@ -59,7 +59,7 @@ public class MaxPropRouterWithEstimation extends ActiveRouter { private Map costsForMessages; /** From host of the last cost calculation */ private DTNHost lastCostFrom; - + /** Over how many samples the "average number of bytes transferred per * transfer opportunity" is taken */ public static int BYTES_TRANSFERRED_AVG_SAMPLES = 10; @@ -68,8 +68,8 @@ public class MaxPropRouterWithEstimation extends ActiveRouter { /** current value for the "avg number of bytes transferred per transfer * opportunity" */ private int avgTransferredBytes = 0; - - /** MaxPROP router's setting namespace ({@value})*/ + + /** MaxPROP router's setting namespace ({@value})*/ public static final String MAXPROP_NS = "MaxPropRouterWithEstimation"; /* Number of seconds in time scale.*/ @@ -90,34 +90,34 @@ public class MaxPropRouterWithEstimation extends ActiveRouter { private Map meetings; private int nrofSamplesIET; private double meanIET; - + /** number of encounters between encounters */ private Map encounters; private int nrofSamplesENC; private double meanENC; private int nrofTotENC; - - /** - * Constructor. Creates a new prototype router based on the settings in - * the given Settings object. - * @param settings The settings object - */ - public MaxPropRouterWithEstimation(Settings settings) { + + /** + * Constructor. Creates a new prototype router based on the settings in + * the given Settings object. + * @param settings The settings object + */ + public MaxPropRouterWithEstimation(Settings settings) { super(settings); Settings maxPropSettings = new Settings(MAXPROP_NS); alpha = DEFAULT_ALPHA; timescale = maxPropSettings.getInt(TIME_SCALE_S); - initMeetings(); + initMeetings(); } - - /** - * Copy constructor. Creates a new router based on the given prototype. - * @param r The router prototype where setting values are copied from - */ - protected MaxPropRouterWithEstimation(MaxPropRouterWithEstimation r) { + + /** + * Copy constructor. Creates a new router based on the given prototype. + * @param r The router prototype where setting values are copied from + */ + protected MaxPropRouterWithEstimation(MaxPropRouterWithEstimation r) { super(r); this.alpha = r.alpha; - this.timescale = r.timescale; + this.timescale = r.timescale; this.probs = new MeetingProbabilitySet( MeetingProbabilitySet.INFINITE_SET_SIZE, this.alpha); this.allProbs = new HashMap(); @@ -125,7 +125,7 @@ protected MaxPropRouterWithEstimation(MaxPropRouterWithEstimation r) { this.ackedMessageIds = new HashSet(); this.avgSamples = new int[BYTES_TRANSFERRED_AVG_SAMPLES]; initMeetings(); - } + } /** * Initializes interencounter estimators @@ -139,14 +139,14 @@ private void initMeetings() { this.nrofSamplesENC = 0; this.nrofTotENC = 0; } - - @Override + + @Override public void changedConnection(Connection con) { super.changedConnection(con); - + if (con.isUp()) { // new connection - this.costsForMessages = null; // invalidate old cost estimates - + this.costsForMessages = null; // invalidate old cost estimates + if (con.isInitiator(getHost())) { /* initiator performs all the actions on behalf of the * other node too (so that the meeting probs are updated @@ -154,28 +154,28 @@ public void changedConnection(Connection con) { DTNHost otherHost = con.getOtherNode(getHost()); MessageRouter mRouter = otherHost.getRouter(); - assert mRouter instanceof MaxPropRouterWithEstimation : "MaxProp only works "+ + assert mRouter instanceof MaxPropRouterWithEstimation : "MaxProp only works "+ " with other routers of same type"; MaxPropRouterWithEstimation otherRouter = (MaxPropRouterWithEstimation)mRouter; - + /* update the estimators */ if (this.updateEstimators(otherHost)) { - this.updateParam(); + this.updateParam(); } if (otherRouter.updateEstimators(getHost())) { otherRouter.updateParam(); } - + /* exchange ACKed message data */ this.ackedMessageIds.addAll(otherRouter.ackedMessageIds); otherRouter.ackedMessageIds.addAll(this.ackedMessageIds); deleteAckedMessages(); otherRouter.deleteAckedMessages(); - + /* update both meeting probabilities */ probs.updateMeetingProbFor(otherHost.getAddress()); otherRouter.probs.updateMeetingProbFor(getHost().getAddress()); - + /* exchange the transitive probabilities */ this.updateTransitiveProbs(otherRouter.allProbs); otherRouter.updateTransitiveProbs(this.allProbs); @@ -188,30 +188,30 @@ public void changedConnection(Connection con) { else { /* connection went down, update transferred bytes average */ updateTransferredBytesAvg(con.getTotalBytesTransferred()); - } - } + } + } /** - * Updates transitive probability values by replacing the current + * Updates transitive probability values by replacing the current * MeetingProbabilitySets with the values from the given mapping * if the given sets have more recent updates. * @param p Mapping of the values of the other host */ private void updateTransitiveProbs(Map p) { for (Map.Entry e : p.entrySet()) { - MeetingProbabilitySet myMps = this.allProbs.get(e.getKey()); - if (myMps == null || + MeetingProbabilitySet myMps = this.allProbs.get(e.getKey()); + if (myMps == null || e.getValue().getLastUpdateTime() > myMps.getLastUpdateTime() ) { this.allProbs.put(e.getKey(), e.getValue().replicate()); } } } - + /** * Updates the MaxPROP estimators * @param host */ - protected boolean updateEstimators(DTNHost host) { + protected boolean updateEstimators(DTNHost host) { /* First estimate the mean InterEncounter Time */ double currentTime = SimClock.getTime(); if (meetings.containsKey(host)) { @@ -225,9 +225,9 @@ protected boolean updateEstimators(DTNHost host) { } else { /* nothing to update */ meetings.put(host,currentTime); - } + } /* Then estimate the number of encounters - * + * */ nrofTotENC++; // the number of encounter if (encounters.containsKey(host)) { @@ -243,7 +243,7 @@ protected boolean updateEstimators(DTNHost host) { /* nothing to update */ encounters.put(host,nrofTotENC); return false; - } + } } /** @@ -262,7 +262,7 @@ protected void updateParam() double eezero; double eeone; double A; - + /* * the estimation algorith does not work for timescales * shorter than the mean IET - so use defaults @@ -271,17 +271,17 @@ protected void updateParam() System.out.printf("meanIET %f > %d timescale\n",meanIET,timescale); return; } - + if (meanIET == 0) { System.out.printf("Mean IET == 0\n"); return; - } - + } + if (meanENC == 0) { System.out.printf("Mean ENC == 0\n"); return; - } - + } + while (ee != err) { A = Math.pow(1+alpha,meanENC+1); fstable = alpha/(A-1); @@ -328,8 +328,8 @@ private void deleteAckedMessages() { this.deleteMessage(id, false); } } - } - + } + @Override public Message messageTransferred(String id, DTNHost from) { this.costsForMessages = null; // new message -> invalidate costs @@ -340,9 +340,9 @@ public Message messageTransferred(String id, DTNHost from) { } return m; } - + /** - * Method is called just before a transfer is finalized + * Method is called just before a transfer is finalized * at {@link ActiveRouter#update()}. MaxProp makes book keeping of the * delivered messages so their IDs are stored. * @param con The connection whose transfer was finalized @@ -351,12 +351,12 @@ public Message messageTransferred(String id, DTNHost from) { protected void transferDone(Connection con) { Message m = con.getMessage(); /* was the message delivered to the final recipient? */ - if (m.getTo() == con.getOtherNode(getHost())) { + if (m.getTo() == con.getOtherNode(getHost())) { this.ackedMessageIds.add(m.getId()); // yes, add to ACKed messages this.deleteMessage(m.getId(), false); // delete from buffer } } - + /** * Updates the average estimate of the number of bytes transferred per * transfer opportunity. @@ -365,19 +365,19 @@ protected void transferDone(Connection con) { private void updateTransferredBytesAvg(int newValue) { int realCount = 0; int sum = 0; - + this.avgSamples[this.nextSampleIndex++] = newValue; if(this.nextSampleIndex >= BYTES_TRANSFERRED_AVG_SAMPLES) { this.nextSampleIndex = 0; } - + for (int i=0; i < BYTES_TRANSFERRED_AVG_SAMPLES; i++) { if (this.avgSamples[i] > 0) { // only values above zero count realCount++; sum += this.avgSamples[i]; } } - + if (realCount > 0) { this.avgTransferredBytes = sum / realCount; } @@ -385,10 +385,10 @@ private void updateTransferredBytesAvg(int newValue) { this.avgTransferredBytes = 0; } } - + /** * Returns the next message that should be dropped, according to MaxProp's - * message ordering scheme (see {@link MaxPropTupleComparator}). + * message ordering scheme (see {@link MaxPropTupleComparator}). * @param excludeMsgBeingSent If true, excludes message(s) that are * being sent from the next-to-be-dropped check (i.e., if next message to * drop is being sent, the following message is returned) @@ -400,42 +400,42 @@ protected Message getNextMessageToRemove(boolean excludeMsgBeingSent) { Collection messages = this.getMessageCollection(); List validMessages = new ArrayList(); - for (Message m : messages) { + for (Message m : messages) { if (excludeMsgBeingSent && isSending(m.getId())) { continue; // skip the message(s) that router is sending } validMessages.add(m); } - - Collections.sort(validMessages, - new MaxPropComparator(this.calcThreshold())); - + + Collections.sort(validMessages, + new MaxPropComparator(this.calcThreshold())); + return validMessages.get(validMessages.size()-1); // return last message } - - @Override - public void update() { - super.update(); - if (!canStartTransfer() ||isTransferring()) { - return; // nothing to transfer or is currently transferring - } - - // try messages that could be delivered to final recipient - if (exchangeDeliverableMessages() != null) { - return; - } - - tryOtherMessages(); + + @Override + public void update() { + super.update(); + if (!canStartTransfer() ||isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + // try messages that could be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; + } + + tryOtherMessages(); } - + /** * Returns the message delivery cost between two hosts from this host's - * point of view. If there is no path between "from" and "to" host, + * point of view. If there is no path between "from" and "to" host, * Double.MAX_VALUE is returned. Paths are calculated only to hosts * that this host has messages to. * @param from The host where a message is coming from * @param to The host where a message would be destined to - * @return The cost of the cheapest path to the destination or + * @return The cost of the cheapest path to the destination or * Double.MAX_VALUE if such a path doesn't exist */ public double getCost(DTNHost from, DTNHost to) { @@ -444,18 +444,18 @@ public double getCost(DTNHost from, DTNHost to) { /* cached costs are invalid -> calculate new costs */ this.allProbs.put(getHost().getAddress(), this.probs); int fromIndex = from.getAddress(); - - /* calculate paths only to nodes we have messages to + + /* calculate paths only to nodes we have messages to * (optimization) */ Set toSet = new HashSet(); for (Message m : getMessageCollection()) { toSet.add(m.getTo().getAddress()); } - + this.costsForMessages = dijkstra.getCosts(fromIndex, toSet); this.lastCostFrom = from; // store source host for caching checks } - + if (costsForMessages.containsKey(to.getAddress())) { return costsForMessages.get(to.getAddress()); } @@ -463,55 +463,55 @@ public double getCost(DTNHost from, DTNHost to) { /* there's no known path to the given host */ return Double.MAX_VALUE; } - } - - /** - * Tries to send all other messages to all connected hosts ordered by + } + + /** + * Tries to send all other messages to all connected hosts ordered by * hop counts and their delivery probability * @return The return value of {@link #tryMessagesForConnected(List)} - */ - private Tuple tryOtherMessages() { - List> messages = - new ArrayList>(); - - Collection msgCollection = getMessageCollection(); - + */ + private Tuple tryOtherMessages() { + List> messages = + new ArrayList>(); + + Collection msgCollection = getMessageCollection(); + /* for all connected hosts that are not transferring at the moment, - * collect all the messages that could be sent */ - for (Connection con : getConnections()) { - DTNHost other = con.getOtherNode(getHost()); - MaxPropRouterWithEstimation othRouter = (MaxPropRouterWithEstimation)other.getRouter(); - - if (othRouter.isTransferring()) { - continue; // skip hosts that are transferring - } - + * collect all the messages that could be sent */ + for (Connection con : getConnections()) { + DTNHost other = con.getOtherNode(getHost()); + MaxPropRouterWithEstimation othRouter = (MaxPropRouterWithEstimation)other.getRouter(); + + if (othRouter.isTransferring()) { + continue; // skip hosts that are transferring + } + for (Message m : msgCollection) { /* skip messages that the other host has or that have - * passed the other host */ + * passed the other host */ if (othRouter.hasMessage(m.getId()) || - m.getHops().contains(other)) { - continue; + m.getHops().contains(other)) { + continue; } - messages.add(new Tuple(m,con)); - } - } - - if (messages.size() == 0) { - return null; - } - + messages.add(new Tuple(m,con)); + } + } + + if (messages.size() == 0) { + return null; + } + /* sort the message-connection tuples according to the criteria - * defined in MaxPropTupleComparator */ - Collections.sort(messages, new MaxPropTupleComparator(calcThreshold())); - return tryMessagesForConnected(messages); - } - + * defined in MaxPropTupleComparator */ + Collections.sort(messages, new MaxPropTupleComparator(calcThreshold())); + return tryMessagesForConnected(messages); + } + /** * Calculates and returns the current threshold value for the buffer's split * based on the average number of bytes transferred per transfer opportunity * and the hop counts of the messages in the buffer. Method is public only - * to make testing easier. + * to make testing easier. * @return current threshold value (hop count) for the buffer's split */ public int calcThreshold() { @@ -524,7 +524,7 @@ public int calcThreshold() { /* can't calc the threshold because there's no transfer data */ return 0; } - + /* calculates the portion (bytes) of the buffer selected for priority */ if (x < b/2) { p = x; @@ -533,9 +533,9 @@ else if (b/2 <= x && x < b) { p = Math.min(x, b-x); } else { - return 0; // no need for the threshold + return 0; // no need for the threshold } - + /* creates a copy of the messages list, sorted by hop count */ ArrayList msgs = new ArrayList(); msgs.addAll(getMessageCollection()); @@ -555,17 +555,17 @@ public int compare(Message m1, Message m2) { for (int n=msgs.size(); i0; i++) { p -= msgs.get(i).getSize(); } - - i--; // the last round moved i one index too far - - /* now i points to the first packet that exceeds portion p; + + i--; // the last round moved i one index too far + + /* now i points to the first packet that exceeds portion p; * the threshold is that packet's hop count + 1 (so that packet and * perhaps some more are included in the priority part) */ return msgs.get(i).getHopCount() + 1; } - + /** - * Message comparator for the MaxProp routing module. + * Message comparator for the MaxProp routing module. * Messages that have a hop count smaller than the given * threshold are given priority and they are ordered by their hop count. * Other messages are ordered by their delivery cost. @@ -574,7 +574,7 @@ private class MaxPropComparator implements Comparator { private int threshold; private DTNHost from1; private DTNHost from2; - + /** * Constructor. Assumes that the host where all the costs are calculated * from is this router's host. @@ -587,11 +587,11 @@ public MaxPropComparator(int treshold) { } /** - * Constructor. + * Constructor. * @param treshold Messages with the hop count smaller than this * value are transferred first (and ordered by the hop count) * @param from1 The host where the cost of msg1 is calculated from - * @param from2 The host where the cost of msg2 is calculated from + * @param from2 The host where the cost of msg2 is calculated from */ public MaxPropComparator(int treshold, DTNHost from1, DTNHost from2) { this.threshold = treshold; @@ -603,11 +603,11 @@ public MaxPropComparator(int treshold, DTNHost from1, DTNHost from2) { * Compares two messages and returns -1 if the first given message * should be first in order, 1 if the second message should be first * or 0 if message order can't be decided. If both messages' hop count - * is less than the threshold, messages are compared by their hop count + * is less than the threshold, messages are compared by their hop count * (smaller is first). If only other's hop count is below the threshold, * that comes first. If both messages are below the threshold, the one - * with smaller cost (determined by - * {@link MaxPropRouterWithEstimation#getCost(DTNHost, DTNHost)}) is first. + * with smaller cost (determined by + * {@link MaxPropRouterWithEstimation#getCost(DTNHost, DTNHost)}) is first. */ public int compare(Message msg1, Message msg2) { double p1, p2; @@ -617,8 +617,8 @@ public int compare(Message msg1, Message msg2) { if (msg1 == msg2) { return 0; } - - /* if one message's hop count is above and the other one's below the + + /* if one message's hop count is above and the other one's below the * threshold, the one below should be sent first */ if (hopc1 < threshold && hopc2 >= threshold) { return -1; // message1 should be first @@ -626,18 +626,18 @@ public int compare(Message msg1, Message msg2) { else if (hopc2 < threshold && hopc1 >= threshold) { return 1; // message2 -"- } - + /* if both are below the threshold, one with lower hop count should * be sent first */ if (hopc1 < threshold && hopc2 < threshold) { return hopc1 - hopc2; } - + /* both messages have more than threshold hops -> cost of the * message path is used for ordering */ p1 = getCost(from1, msg1.getTo()); p2 = getCost(from2, msg2.getTo()); - + /* the one with lower cost should be sent first */ if (p1-p2 == 0) { /* if costs are equal, hop count breaks ties. If even hop counts @@ -646,7 +646,7 @@ else if (hopc2 < threshold && hopc1 >= threshold) { return compareByQueueMode(msg1, msg2); } else { - return hopc1 - hopc2; + return hopc1 - hopc2; } } else if (p1-p2 < 0) { @@ -655,68 +655,68 @@ else if (p1-p2 < 0) { else { return 1; // msg2 had the smaller cost } - } + } } - - /** - * Message-Connection tuple comparator for the MaxProp routing + + /** + * Message-Connection tuple comparator for the MaxProp routing * module. Uses {@link MaxPropComparator} on the messages of the tuples * setting the "from" host for that message to be the one in the connection - * tuple (i.e., path is calculated starting from the host on the other end - * of the connection). - */ - private class MaxPropTupleComparator + * tuple (i.e., path is calculated starting from the host on the other end + * of the connection). + */ + private class MaxPropTupleComparator implements Comparator > { private int threshold; - + public MaxPropTupleComparator(int threshold) { this.threshold = threshold; - } - + } + /** - * Compares two message-connection tuples using the + * Compares two message-connection tuples using the * {@link MaxPropComparator#compare(Message, Message)}. */ - public int compare(Tuple tuple1, + public int compare(Tuple tuple1, Tuple tuple2) { MaxPropComparator comp; DTNHost from1 = tuple1.getValue().getOtherNode(getHost()); DTNHost from2 = tuple2.getValue().getOtherNode(getHost()); - + comp = new MaxPropComparator(threshold, from1, from2); - return comp.compare(tuple1.getKey(), tuple2.getKey()); - } + return comp.compare(tuple1.getKey(), tuple2.getKey()); + } } - - - @Override - public RoutingInfo getRoutingInfo() { - RoutingInfo top = super.getRoutingInfo(); - RoutingInfo ri = new RoutingInfo(probs.getAllProbs().size() + - " meeting probabilities"); - - /* show meeting probabilities for this host */ - for (Map.Entry e : probs.getAllProbs().entrySet()) { - Integer host = e.getKey(); - Double value = e.getValue(); - ri.addMoreInfo(new RoutingInfo(String.format("host %d : %.6f", - host, value))); - } - + + + @Override + public RoutingInfo getRoutingInfo() { + RoutingInfo top = super.getRoutingInfo(); + RoutingInfo ri = new RoutingInfo(probs.getAllProbs().size() + + " meeting probabilities"); + + /* show meeting probabilities for this host */ + for (Map.Entry e : probs.getAllProbs().entrySet()) { + Integer host = e.getKey(); + Double value = e.getValue(); + ri.addMoreInfo(new RoutingInfo(String.format("host %d : %.6f", + host, value))); + } + ri.addMoreInfo(new RoutingInfo(String.format("meanIET: %f\t from %d samples",meanIET,nrofSamplesIET))); ri.addMoreInfo(new RoutingInfo(String.format("meanENC: %f\t from %d samples",meanENC,nrofSamplesENC))); ri.addMoreInfo(new RoutingInfo(String.format("current alpha: %f",alpha))); - + top.addMoreInfo(ri); - top.addMoreInfo(new RoutingInfo("Avg transferred bytes: " + + top.addMoreInfo(new RoutingInfo("Avg transferred bytes: " + this.avgTransferredBytes)); - - return top; - } - - @Override - public MessageRouter replicate() { - MaxPropRouterWithEstimation r = new MaxPropRouterWithEstimation(this); - return r; - } -} \ No newline at end of file + + return top; + } + + @Override + public MessageRouter replicate() { + MaxPropRouterWithEstimation r = new MaxPropRouterWithEstimation(this); + return r; + } +} diff --git a/routing/MessageRouter.java b/routing/MessageRouter.java index 4e6d2913c..dc809b30f 100644 --- a/routing/MessageRouter.java +++ b/routing/MessageRouter.java @@ -1,8 +1,8 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; +package routing; import java.util.Collection; import java.util.Collections; @@ -25,51 +25,51 @@ import core.SettingsError; import core.SimClock; import core.SimError; - -/** - * Superclass for message routers. - */ -public abstract class MessageRouter { - /** Message buffer size -setting id ({@value}). Integer value in bytes.*/ + +/** + * Superclass for message routers. + */ +public abstract class MessageRouter { + /** Message buffer size -setting id ({@value}). Integer value in bytes.*/ public static final String B_SIZE_S = "bufferSize"; /** * Message TTL -setting id ({@value}). Value is in minutes and must be - * an integer. - */ + * an integer. + */ public static final String MSG_TTL_S = "msgTtl"; /** - * Message/fragment sending queue type -setting id ({@value}). + * Message/fragment sending queue type -setting id ({@value}). * This setting affects the order the messages and fragments are sent if the - * routing protocol doesn't define any particular order (e.g, if more than - * one message can be sent directly to the final recipient). + * routing protocol doesn't define any particular order (e.g, if more than + * one message can be sent directly to the final recipient). * Valid values are
*

    *
  • 1 : random (message order is randomized every time; default option) *
  • 2 : FIFO (most recently received messages are sent last) *
- */ + */ public static final String SEND_QUEUE_MODE_S = "sendQueue"; - + /** Setting value for random queue mode */ public static final int Q_MODE_RANDOM = 1; /** Setting value for FIFO queue mode */ public static final int Q_MODE_FIFO = 2; - + /* Return values when asking to start a transmission: - * RCV_OK (0) means that the host accepts the message and transfer started, - * values < 0 mean that the receiving host will not accept this - * particular message (right now), - * values > 0 mean the host will not right now accept any message. + * RCV_OK (0) means that the host accepts the message and transfer started, + * values < 0 mean that the receiving host will not accept this + * particular message (right now), + * values > 0 mean the host will not right now accept any message. * Values in the range [-100, 100] are reserved for general return values - * (and specified here), values beyond that are free for use in + * (and specified here), values beyond that are free for use in * implementation specific cases */ - /** Receive return value for OK */ - public static final int RCV_OK = 0; - /** Receive return value for busy receiver */ - public static final int TRY_LATER_BUSY = 1; - /** Receive return value for an old (already received) message */ - public static final int DENIED_OLD = -1; - /** Receive return value for not enough space in the buffer for the msg */ + /** Receive return value for OK */ + public static final int RCV_OK = 0; + /** Receive return value for busy receiver */ + public static final int TRY_LATER_BUSY = 1; + /** Receive return value for an old (already received) message */ + public static final int DENIED_OLD = -1; + /** Receive return value for not enough space in the buffer for the msg */ public static final int DENIED_NO_SPACE = -2; /** Receive return value for messages whose TTL has expired */ public static final int DENIED_TTL = -3; @@ -79,80 +79,80 @@ public abstract class MessageRouter { public static final int DENIED_POLICY = -5; /** Receive return value for unspecified reason */ public static final int DENIED_UNSPECIFIED = -99; - - private List mListeners; - /** The messages being transferred with msgID_hostName keys */ - private HashMap incomingMessages; - /** The messages this router is carrying */ - private HashMap messages; - /** The messages this router has received as the final recipient */ + + private List mListeners; + /** The messages being transferred with msgID_hostName keys */ + private HashMap incomingMessages; + /** The messages this router is carrying */ + private HashMap messages; + /** The messages this router has received as the final recipient */ private HashMap deliveredMessages; /** The messages that Applications on this router have blacklisted */ - private HashMap blacklistedMessages; - /** Host where this router belongs to */ - private DTNHost host; - /** size of the buffer */ - private int bufferSize; - /** TTL for all messages */ + private HashMap blacklistedMessages; + /** Host where this router belongs to */ + private DTNHost host; + /** size of the buffer */ + private int bufferSize; + /** TTL for all messages */ protected int msgTtl; /** Queue mode for sending messages */ private int sendQueueMode; /** applications attached to the host */ private HashMap> applications = null; - - /** - * Constructor. Creates a new message router based on the settings in - * the given Settings object. Size of the message buffer is read from - * {@link #B_SIZE_S} setting. Default value is Integer.MAX_VALUE. - * @param s The settings object - */ - public MessageRouter(Settings s) { - this.bufferSize = Integer.MAX_VALUE; // defaults to rather large buffer - this.msgTtl = Message.INFINITE_TTL; + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. Size of the message buffer is read from + * {@link #B_SIZE_S} setting. Default value is Integer.MAX_VALUE. + * @param s The settings object + */ + public MessageRouter(Settings s) { + this.bufferSize = Integer.MAX_VALUE; // defaults to rather large buffer + this.msgTtl = Message.INFINITE_TTL; this.applications = new HashMap>(); - - if (s.contains(B_SIZE_S)) { - this.bufferSize = s.getInt(B_SIZE_S); - } - if (s.contains(MSG_TTL_S)) { - this.msgTtl = s.getInt(MSG_TTL_S); + + if (s.contains(B_SIZE_S)) { + this.bufferSize = s.getInt(B_SIZE_S); + } + if (s.contains(MSG_TTL_S)) { + this.msgTtl = s.getInt(MSG_TTL_S); } if (s.contains(SEND_QUEUE_MODE_S)) { this.sendQueueMode = s.getInt(SEND_QUEUE_MODE_S); if (sendQueueMode < 1 || sendQueueMode > 2) { - throw new SettingsError("Invalid value for " + + throw new SettingsError("Invalid value for " + s.getFullPropertyName(SEND_QUEUE_MODE_S)); } } else { sendQueueMode = Q_MODE_RANDOM; } - - } - - /** - * Initializes the router; i.e. sets the host this router is in and - * message listeners that need to be informed about message related - * events etc. - * @param host The host this router is in - * @param mListeners The message listeners - */ - public void init(DTNHost host, List mListeners) { - this.incomingMessages = new HashMap(); - this.messages = new HashMap(); + + } + + /** + * Initializes the router; i.e. sets the host this router is in and + * message listeners that need to be informed about message related + * events etc. + * @param host The host this router is in + * @param mListeners The message listeners + */ + public void init(DTNHost host, List mListeners) { + this.incomingMessages = new HashMap(); + this.messages = new HashMap(); this.deliveredMessages = new HashMap(); - this.blacklistedMessages = new HashMap(); - this.mListeners = mListeners; - this.host = host; - } - - /** - * Copy-constructor. - * @param r Router to copy the settings from. - */ - protected MessageRouter(MessageRouter r) { - this.bufferSize = r.bufferSize; + this.blacklistedMessages = new HashMap(); + this.mListeners = mListeners; + this.host = host; + } + + /** + * Copy-constructor. + * @param r Router to copy the settings from. + */ + protected MessageRouter(MessageRouter r) { + this.bufferSize = r.bufferSize; this.msgTtl = r.msgTtl; this.sendQueueMode = r.sendQueueMode; @@ -162,194 +162,194 @@ protected MessageRouter(MessageRouter r) { addApplication(app.replicate()); } } - } - - /** - * Updates router. - * This method should be called (at least once) on every simulation - * interval to update the status of transfer(s). - */ + } + + /** + * Updates router. + * This method should be called (at least once) on every simulation + * interval to update the status of transfer(s). + */ public void update(){ for (Collection apps : this.applications.values()) { for (Application app : apps) { app.update(this.host); } } - } - - /** - * Informs the router about change in connections state. - * @param con The connection that changed - */ - public abstract void changedConnection(Connection con); - - /** - * Returns a message by ID. - * @param id ID of the message - * @return The message - */ - protected Message getMessage(String id) { - return this.messages.get(id); - } - - /** - * Checks if this router has a message with certain id buffered. - * @param id Identifier of the message - * @return True if the router has message with this id, false if not - */ - public boolean hasMessage(String id) { - return this.messages.containsKey(id); - } - - /** + } + + /** + * Informs the router about change in connections state. + * @param con The connection that changed + */ + public abstract void changedConnection(Connection con); + + /** + * Returns a message by ID. + * @param id ID of the message + * @return The message + */ + protected Message getMessage(String id) { + return this.messages.get(id); + } + + /** + * Checks if this router has a message with certain id buffered. + * @param id Identifier of the message + * @return True if the router has message with this id, false if not + */ + public boolean hasMessage(String id) { + return this.messages.containsKey(id); + } + + /** * Returns true if a full message with same ID as the given message has been - * received by this host as the final recipient - * (at least once). - * @param m message we're interested of - * @return true if a message with the same ID has been received by - * this host as the final recipient. - */ - protected boolean isDeliveredMessage(Message m) { - return (this.deliveredMessages.containsKey(m.getId())); - } - - /** + * received by this host as the final recipient + * (at least once). + * @param m message we're interested of + * @return true if a message with the same ID has been received by + * this host as the final recipient. + */ + protected boolean isDeliveredMessage(Message m) { + return (this.deliveredMessages.containsKey(m.getId())); + } + + /** * Returns true if the message has been blacklisted. Messages * get blacklisted when an application running on the node wants to drop it. * This ensures the peer doesn't try to constantly send the same message to * this node, just to get dropped by an application every time. - * + * * @param id id of the message * @return true if blacklisted, false otherwise. */ protected boolean isBlacklistedMessage(String id) { return this.blacklistedMessages.containsKey(id); } - - /** + + /** * Returns a reference to the messages of this router in collection. * Note: If there's a chance that some message(s) from the collection * could be deleted (or added) while iterating through the collection, a * copy of the collection should be made to avoid concurrent modification - * exceptions. - * @return a reference to the messages of this router in collection - */ - public Collection getMessageCollection() { - return this.messages.values(); - } - - /** - * Returns the number of messages this router has - * @return How many messages this router has - */ - public int getNrofMessages() { - return this.messages.size(); - } - - /** - * Returns the size of the message buffer. - * @return The size or Integer.MAX_VALUE if the size isn't defined. - */ - public int getBufferSize() { - return this.bufferSize; - } - - /** - * Returns the amount of free space in the buffer. May return a negative - * value if there are more messages in the buffer than should fit there - * (because of creating new messages). - * @return The amount of free space (Integer.MAX_VALUE if the buffer - * size isn't defined) - */ - public int getFreeBufferSize() { - int occupancy = 0; - - if (this.getBufferSize() == Integer.MAX_VALUE) { - return Integer.MAX_VALUE; - } - - for (Message m : getMessageCollection()) { - occupancy += m.getSize(); - } - - return this.getBufferSize() - occupancy; - } - - /** - * Returns the host this router is in - * @return The host object - */ - protected DTNHost getHost() { - return this.host; - } - - /** - * Start sending a message to another host. - * @param id Id of the message to send - * @param to The host to send the message to - */ - public void sendMessage(String id, DTNHost to) { - Message m = getMessage(id); - Message m2; - if (m == null) throw new SimError("no message for id " + - id + " to send at " + this.host); - - m2 = m.replicate(); // send a replicate of the message - to.receiveMessage(m2, this.host); - } - - /** - * Requests for deliverable message from this router to be sent trough a - * connection. - * @param con The connection to send the messages trough - * @return True if this router started a transfer, false if not - */ - public boolean requestDeliverableMessages(Connection con) { - return false; // default behavior is to not start -- subclasses override - } - - /** - * Try to start receiving a message from another host. - * @param m Message to put in the receiving buffer - * @param from Who the message is from - * @return Value zero if the node accepted the message (RCV_OK), value less - * than zero if node rejected the message (e.g. DENIED_OLD), value bigger - * than zero if the other node should try later (e.g. TRY_LATER_BUSY). - */ + * exceptions. + * @return a reference to the messages of this router in collection + */ + public Collection getMessageCollection() { + return this.messages.values(); + } + + /** + * Returns the number of messages this router has + * @return How many messages this router has + */ + public int getNrofMessages() { + return this.messages.size(); + } + + /** + * Returns the size of the message buffer. + * @return The size or Integer.MAX_VALUE if the size isn't defined. + */ + public int getBufferSize() { + return this.bufferSize; + } + + /** + * Returns the amount of free space in the buffer. May return a negative + * value if there are more messages in the buffer than should fit there + * (because of creating new messages). + * @return The amount of free space (Integer.MAX_VALUE if the buffer + * size isn't defined) + */ + public int getFreeBufferSize() { + int occupancy = 0; + + if (this.getBufferSize() == Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + + for (Message m : getMessageCollection()) { + occupancy += m.getSize(); + } + + return this.getBufferSize() - occupancy; + } + + /** + * Returns the host this router is in + * @return The host object + */ + protected DTNHost getHost() { + return this.host; + } + + /** + * Start sending a message to another host. + * @param id Id of the message to send + * @param to The host to send the message to + */ + public void sendMessage(String id, DTNHost to) { + Message m = getMessage(id); + Message m2; + if (m == null) throw new SimError("no message for id " + + id + " to send at " + this.host); + + m2 = m.replicate(); // send a replicate of the message + to.receiveMessage(m2, this.host); + } + + /** + * Requests for deliverable message from this router to be sent trough a + * connection. + * @param con The connection to send the messages trough + * @return True if this router started a transfer, false if not + */ + public boolean requestDeliverableMessages(Connection con) { + return false; // default behavior is to not start -- subclasses override + } + + /** + * Try to start receiving a message from another host. + * @param m Message to put in the receiving buffer + * @param from Who the message is from + * @return Value zero if the node accepted the message (RCV_OK), value less + * than zero if node rejected the message (e.g. DENIED_OLD), value bigger + * than zero if the other node should try later (e.g. TRY_LATER_BUSY). + */ public int receiveMessage(Message m, DTNHost from) { Message newMessage = m.replicate(); - - this.putToIncomingBuffer(newMessage, from); + + this.putToIncomingBuffer(newMessage, from); newMessage.addNodeOnPath(this.host); - - for (MessageListener ml : this.mListeners) { - ml.messageTransferStarted(newMessage, from, getHost()); - } - - return RCV_OK; // superclass always accepts messages - } - - /** - * This method should be called (on the receiving host) after a message - * was successfully transferred. The transferred message is put to the - * message buffer unless this host is the final recipient of the message. - * @param id Id of the transferred message - * @param from Host the message was from (previous hop) - * @return The message that this host received - */ - public Message messageTransferred(String id, DTNHost from) { - Message incoming = removeFromIncomingBuffer(id, from); - boolean isFinalRecipient; + + for (MessageListener ml : this.mListeners) { + ml.messageTransferStarted(newMessage, from, getHost()); + } + + return RCV_OK; // superclass always accepts messages + } + + /** + * This method should be called (on the receiving host) after a message + * was successfully transferred. The transferred message is put to the + * message buffer unless this host is the final recipient of the message. + * @param id Id of the transferred message + * @param from Host the message was from (previous hop) + * @return The message that this host received + */ + public Message messageTransferred(String id, DTNHost from) { + Message incoming = removeFromIncomingBuffer(id, from); + boolean isFinalRecipient; boolean isFirstDelivery; // is this first delivered instance of the msg - - + + if (incoming == null) { throw new SimError("No message with ID " + id + " in the incoming "+ "buffer of " + this.host); } - + incoming.setReceiveTime(SimClock.getTime()); - + // Pass the message to the application (if any) and get outgoing message Message outgoing = incoming; for (Application app : getApplications(incoming.getAppID())) { @@ -358,7 +358,7 @@ public Message messageTransferred(String id, DTNHost from) { outgoing = app.handle(outgoing, this.host); if (outgoing == null) break; // Some app wanted to drop the message } - + Message aMessage = (outgoing==null)?(incoming):(outgoing); // If the application re-targets the message (changes 'to') // then the message is not considered as 'delivered' to this host. @@ -377,36 +377,36 @@ public Message messageTransferred(String id, DTNHost from) { // Otherwise the peer will just try to send it back again. this.blacklistedMessages.put(id, null); } - + for (MessageListener ml : this.mListeners) { ml.messageTransferred(aMessage, from, this.host, isFirstDelivery); - } - - return aMessage; - } - - /** - * Puts a message to incoming messages buffer. Two messages with the - * same ID are distinguished by the from host. - * @param m The message to put - * @param from Who the message was from (previous hop). - */ - protected void putToIncomingBuffer(Message m, DTNHost from) { - this.incomingMessages.put(m.getId() + "_" + from.toString(), m); - } - - /** - * Removes and returns a message with a certain ID from the incoming - * messages buffer or null if such message wasn't found. - * @param id ID of the message - * @param from The host that sent this message (previous hop) - * @return The found message or null if such message wasn't found - */ - protected Message removeFromIncomingBuffer(String id, DTNHost from) { - return this.incomingMessages.remove(id + "_" + from.toString()); + } + + return aMessage; + } + + /** + * Puts a message to incoming messages buffer. Two messages with the + * same ID are distinguished by the from host. + * @param m The message to put + * @param from Who the message was from (previous hop). + */ + protected void putToIncomingBuffer(Message m, DTNHost from) { + this.incomingMessages.put(m.getId() + "_" + from.toString(), m); + } + + /** + * Removes and returns a message with a certain ID from the incoming + * messages buffer or null if such message wasn't found. + * @param id ID of the message + * @param from The host that sent this message (previous hop) + * @return The found message or null if such message wasn't found + */ + protected Message removeFromIncomingBuffer(String id, DTNHost from) { + return this.incomingMessages.remove(id + "_" + from.toString()); } - + /** * Returns true if a message with the given ID is one of the * currently incoming messages, false if not @@ -415,89 +415,89 @@ protected Message removeFromIncomingBuffer(String id, DTNHost from) { */ protected boolean isIncomingMessage(String id) { return this.incomingMessages.containsKey(id); - } - - /** - * Adds a message to the message buffer and informs message listeners - * about new message (if requested). - * @param m The message to add - * @param newMessage If true, message listeners are informed about a new - * message, if false, nothing is informed. - */ - protected void addToMessages(Message m, boolean newMessage) { - this.messages.put(m.getId(), m); - - if (newMessage) { - for (MessageListener ml : this.mListeners) { - ml.newMessage(m); - } - } - } - - /** - * Removes and returns a message from the message buffer. - * @param id Identifier of the message to remove - * @return The removed message or null if message for the ID wasn't found - */ - protected Message removeFromMessages(String id) { - Message m = this.messages.remove(id); - return m; - } - - /** - * This method should be called (on the receiving host) when a message - * transfer was aborted. - * @param id Id of the message that was being transferred + } + + /** + * Adds a message to the message buffer and informs message listeners + * about new message (if requested). + * @param m The message to add + * @param newMessage If true, message listeners are informed about a new + * message, if false, nothing is informed. + */ + protected void addToMessages(Message m, boolean newMessage) { + this.messages.put(m.getId(), m); + + if (newMessage) { + for (MessageListener ml : this.mListeners) { + ml.newMessage(m); + } + } + } + + /** + * Removes and returns a message from the message buffer. + * @param id Identifier of the message to remove + * @return The removed message or null if message for the ID wasn't found + */ + protected Message removeFromMessages(String id) { + Message m = this.messages.remove(id); + return m; + } + + /** + * This method should be called (on the receiving host) when a message + * transfer was aborted. + * @param id Id of the message that was being transferred * @param from Host the message was from (previous hop) * @param bytesRemaining Nrof bytes that were left before the transfer - * would have been ready; or -1 if the number of bytes is not known - */ - public void messageAborted(String id, DTNHost from, int bytesRemaining) { - Message incoming = removeFromIncomingBuffer(id, from); - if (incoming == null) { - throw new SimError("No incoming message for id " + id + - " to abort in " + this.host); - } - - for (MessageListener ml : this.mListeners) { - ml.messageTransferAborted(incoming, from, this.host); + * would have been ready; or -1 if the number of bytes is not known + */ + public void messageAborted(String id, DTNHost from, int bytesRemaining) { + Message incoming = removeFromIncomingBuffer(id, from); + if (incoming == null) { + throw new SimError("No incoming message for id " + id + + " to abort in " + this.host); } - } - - /** - * Creates a new message to the router. + + for (MessageListener ml : this.mListeners) { + ml.messageTransferAborted(incoming, from, this.host); + } + } + + /** + * Creates a new message to the router. * @param m The message to create - * @return True if the creation succeeded, false if not (e.g. - * the message was too big for the buffer) - */ + * @return True if the creation succeeded, false if not (e.g. + * the message was too big for the buffer) + */ public boolean createNewMessage(Message m) { - m.setTtl(this.msgTtl); - addToMessages(m, true); - return true; - } - - /** + m.setTtl(this.msgTtl); + addToMessages(m, true); + return true; + } + + /** * Deletes a message from the buffer and informs message listeners - * about the event - * @param id Identifier of the message to delete - * @param drop If the message is dropped (e.g. because of full buffer) this - * should be set to true. False value indicates e.g. remove of message - * because it was delivered to final destination. - */ - public void deleteMessage(String id, boolean drop) { - Message removed = removeFromMessages(id); - if (removed == null) throw new SimError("no message for id " + - id + " to remove at " + this.host); - - for (MessageListener ml : this.mListeners) { - ml.messageDeleted(removed, this.host, drop); - } - } - - /** - * Sorts/shuffles the given list according to the current sending queue - * mode. The list can contain either Message or Tuple - * objects. Other objects cause error. + * about the event + * @param id Identifier of the message to delete + * @param drop If the message is dropped (e.g. because of full buffer) this + * should be set to true. False value indicates e.g. remove of message + * because it was delivered to final destination. + */ + public void deleteMessage(String id, boolean drop) { + Message removed = removeFromMessages(id); + if (removed == null) throw new SimError("no message for id " + + id + " to remove at " + this.host); + + for (MessageListener ml : this.mListeners) { + ml.messageDeleted(removed, this.host, drop); + } + } + + /** + * Sorts/shuffles the given list according to the current sending queue + * mode. The list can contain either Message or Tuple + * objects. Other objects cause error. * @param list The list to sort or shuffle * @return The sorted/shuffled list */ @@ -508,13 +508,13 @@ protected List sortByQueueMode(List list) { Collections.shuffle(list, new Random(SimClock.getIntTime())); break; case Q_MODE_FIFO: - Collections.sort(list, + Collections.sort(list, new Comparator() { /** Compares two tuples by their messages' receiving time */ public int compare(Object o1, Object o2) { double diff; Message m1, m2; - + if (o1 instanceof Tuple) { m1 = ((Tuple)o1).getKey(); m2 = ((Tuple)o2).getKey(); @@ -524,10 +524,10 @@ else if (o1 instanceof Message) { m2 = (Message)o2; } else { - throw new SimError("Invalid type of objects in " + + throw new SimError("Invalid type of objects in " + "the list"); } - + diff = m1.getReceiveTime() - m2.getReceiveTime(); if (diff == 0) { return 0; @@ -540,23 +540,23 @@ else if (o1 instanceof Message) { default: throw new SimError("Unknown queue mode " + sendQueueMode); } - + return list; } /** * Gives the order of the two given messages as defined by the current - * queue mode + * queue mode * @param m1 The first message * @param m2 The second message - * @return -1 if the first message should come first, 1 if the second + * @return -1 if the first message should come first, 1 if the second * message should come first, or 0 if the ordering isn't defined */ protected int compareByQueueMode(Message m1, Message m2) { switch (sendQueueMode) { case Q_MODE_RANDOM: /* return randomly (enough) but consistently -1, 0 or 1 */ - return (m1.hashCode()/2 + m2.hashCode()/2) % 3 - 1; + return (m1.hashCode()/2 + m2.hashCode()/2) % 3 - 1; case Q_MODE_FIFO: double diff = m1.getReceiveTime() - m2.getReceiveTime(); if (diff == 0) { @@ -568,43 +568,43 @@ protected int compareByQueueMode(Message m1, Message m2) { throw new SimError("Unknown queue mode " + sendQueueMode); } } - - /** - * Returns routing information about this router. - * @return The routing information. - */ - public RoutingInfo getRoutingInfo() { - RoutingInfo ri = new RoutingInfo(this); - RoutingInfo incoming = new RoutingInfo(this.incomingMessages.size() + - " incoming message(s)"); - RoutingInfo delivered = new RoutingInfo(this.deliveredMessages.size() + - " delivered message(s)"); - - RoutingInfo cons = new RoutingInfo(host.getConnections().size() + - " connection(s)"); - - ri.addMoreInfo(incoming); - ri.addMoreInfo(delivered); - ri.addMoreInfo(cons); - - for (Message m : this.incomingMessages.values()) { - incoming.addMoreInfo(new RoutingInfo(m)); - } - - for (Message m : this.deliveredMessages.values()) { - delivered.addMoreInfo(new RoutingInfo(m + " path:" + m.getHops())); - } - - for (Connection c : host.getConnections()) { - cons.addMoreInfo(new RoutingInfo(c)); - } - - return ri; + + /** + * Returns routing information about this router. + * @return The routing information. + */ + public RoutingInfo getRoutingInfo() { + RoutingInfo ri = new RoutingInfo(this); + RoutingInfo incoming = new RoutingInfo(this.incomingMessages.size() + + " incoming message(s)"); + RoutingInfo delivered = new RoutingInfo(this.deliveredMessages.size() + + " delivered message(s)"); + + RoutingInfo cons = new RoutingInfo(host.getConnections().size() + + " connection(s)"); + + ri.addMoreInfo(incoming); + ri.addMoreInfo(delivered); + ri.addMoreInfo(cons); + + for (Message m : this.incomingMessages.values()) { + incoming.addMoreInfo(new RoutingInfo(m)); + } + + for (Message m : this.deliveredMessages.values()) { + delivered.addMoreInfo(new RoutingInfo(m + " path:" + m.getHops())); + } + + for (Connection c : host.getConnections()) { + cons.addMoreInfo(new RoutingInfo(c)); + } + + return ri; } - - /** + + /** * Adds an application to the attached applications list. - * + * * @param app The application to attach to this router. */ public void addApplication(Application app) { @@ -614,11 +614,11 @@ public void addApplication(Application app) { } this.applications.get(app.getAppID()).add(app); } - - /** + + /** * Returns all the applications that want to receive messages for the given * application ID. - * + * * @param ID The application ID or null for all apps. * @return A list of all applications that want to receive the message. */ @@ -639,20 +639,20 @@ public Collection getApplications(String ID) { return apps; } - /** - * Creates a replicate of this router. The replicate has the same - * settings as this router but empty buffers and routing tables. - * @return The replicate - */ - public abstract MessageRouter replicate(); - - /** - * Returns a String presentation of this router - * @return A String presentation of this router - */ - public String toString() { - return getClass().getSimpleName() + " of " + - this.getHost().toString() + " with " + getNrofMessages() - + " messages"; - } -} + /** + * Creates a replicate of this router. The replicate has the same + * settings as this router but empty buffers and routing tables. + * @return The replicate + */ + public abstract MessageRouter replicate(); + + /** + * Returns a String presentation of this router + * @return A String presentation of this router + */ + public String toString() { + return getClass().getSimpleName() + " of " + + this.getHost().toString() + " with " + getNrofMessages() + + " messages"; + } +} diff --git a/routing/PassiveRouter.java b/routing/PassiveRouter.java index d4c830abe..4e41536da 100644 --- a/routing/PassiveRouter.java +++ b/routing/PassiveRouter.java @@ -1,43 +1,43 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; - +package routing; + import core.Connection; import core.Settings; - -/** - * Passive router that doesn't send anything unless commanded. This is useful - * for external event -controlled routing or dummy nodes. - * For implementation specifics, see MessageRouter class. - */ -public class PassiveRouter extends MessageRouter { - - public PassiveRouter(Settings s) { - super(s); - } - - /** - * Copy-constructor. - * @param r Router to copy the settings from. - */ - protected PassiveRouter(PassiveRouter r) { - super(r); - } - - @Override - public void update() { - super.update(); - } - - @Override - public void changedConnection(Connection con) { - // -"- - } - - @Override - public MessageRouter replicate() { - return new PassiveRouter(this); - } -} + +/** + * Passive router that doesn't send anything unless commanded. This is useful + * for external event -controlled routing or dummy nodes. + * For implementation specifics, see MessageRouter class. + */ +public class PassiveRouter extends MessageRouter { + + public PassiveRouter(Settings s) { + super(s); + } + + /** + * Copy-constructor. + * @param r Router to copy the settings from. + */ + protected PassiveRouter(PassiveRouter r) { + super(r); + } + + @Override + public void update() { + super.update(); + } + + @Override + public void changedConnection(Connection con) { + // -"- + } + + @Override + public MessageRouter replicate() { + return new PassiveRouter(this); + } +} diff --git a/routing/ProphetRouter.java b/routing/ProphetRouter.java index 3dda01446..40738cdf6 100644 --- a/routing/ProphetRouter.java +++ b/routing/ProphetRouter.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; - +package routing; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -21,288 +21,288 @@ import core.Message; import core.Settings; import core.SimClock; - -/** - * Implementation of PRoPHET router as described in - * Probabilistic routing in intermittently connected networks by - * Anders Lindgren et al. - */ -public class ProphetRouter extends ActiveRouter { - /** delivery predictability initialization constant*/ - public static final double P_INIT = 0.75; - /** delivery predictability transitivity scaling constant default value */ - public static final double DEFAULT_BETA = 0.25; - /** delivery predictability aging constant */ - public static final double GAMMA = 0.98; - - /** Prophet router's setting namespace ({@value})*/ - public static final String PROPHET_NS = "ProphetRouter"; - /** - * Number of seconds in time unit -setting id ({@value}). - * How many seconds one time unit is when calculating aging of - * delivery predictions. Should be tweaked for the scenario.*/ - public static final String SECONDS_IN_UNIT_S ="secondsInTimeUnit"; - - /** - * Transitivity scaling constant (beta) -setting id ({@value}). - * Default value for setting is {@link #DEFAULT_BETA}. - */ - public static final String BETA_S = "beta"; - - /** the value of nrof seconds in time unit -setting */ - private int secondsInTimeUnit; - /** value of beta setting */ - private double beta; - - /** delivery predictabilities */ - private Map preds; - /** last delivery predictability update (sim)time */ - private double lastAgeUpdate; - - /** - * Constructor. Creates a new message router based on the settings in - * the given Settings object. - * @param s The settings object - */ - public ProphetRouter(Settings s) { - super(s); - Settings prophetSettings = new Settings(PROPHET_NS); - secondsInTimeUnit = prophetSettings.getInt(SECONDS_IN_UNIT_S); - if (prophetSettings.contains(BETA_S)) { - beta = prophetSettings.getDouble(BETA_S); - } - else { - beta = DEFAULT_BETA; - } - - initPreds(); - } - - /** - * Copyconstructor. - * @param r The router prototype where setting values are copied from - */ - protected ProphetRouter(ProphetRouter r) { - super(r); - this.secondsInTimeUnit = r.secondsInTimeUnit; - this.beta = r.beta; - initPreds(); - } - - /** - * Initializes predictability hash - */ - private void initPreds() { - this.preds = new HashMap(); - } - - @Override + +/** + * Implementation of PRoPHET router as described in + * Probabilistic routing in intermittently connected networks by + * Anders Lindgren et al. + */ +public class ProphetRouter extends ActiveRouter { + /** delivery predictability initialization constant*/ + public static final double P_INIT = 0.75; + /** delivery predictability transitivity scaling constant default value */ + public static final double DEFAULT_BETA = 0.25; + /** delivery predictability aging constant */ + public static final double GAMMA = 0.98; + + /** Prophet router's setting namespace ({@value})*/ + public static final String PROPHET_NS = "ProphetRouter"; + /** + * Number of seconds in time unit -setting id ({@value}). + * How many seconds one time unit is when calculating aging of + * delivery predictions. Should be tweaked for the scenario.*/ + public static final String SECONDS_IN_UNIT_S ="secondsInTimeUnit"; + + /** + * Transitivity scaling constant (beta) -setting id ({@value}). + * Default value for setting is {@link #DEFAULT_BETA}. + */ + public static final String BETA_S = "beta"; + + /** the value of nrof seconds in time unit -setting */ + private int secondsInTimeUnit; + /** value of beta setting */ + private double beta; + + /** delivery predictabilities */ + private Map preds; + /** last delivery predictability update (sim)time */ + private double lastAgeUpdate; + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public ProphetRouter(Settings s) { + super(s); + Settings prophetSettings = new Settings(PROPHET_NS); + secondsInTimeUnit = prophetSettings.getInt(SECONDS_IN_UNIT_S); + if (prophetSettings.contains(BETA_S)) { + beta = prophetSettings.getDouble(BETA_S); + } + else { + beta = DEFAULT_BETA; + } + + initPreds(); + } + + /** + * Copyconstructor. + * @param r The router prototype where setting values are copied from + */ + protected ProphetRouter(ProphetRouter r) { + super(r); + this.secondsInTimeUnit = r.secondsInTimeUnit; + this.beta = r.beta; + initPreds(); + } + + /** + * Initializes predictability hash + */ + private void initPreds() { + this.preds = new HashMap(); + } + + @Override public void changedConnection(Connection con) { super.changedConnection(con); - - if (con.isUp()) { - DTNHost otherHost = con.getOtherNode(getHost()); - updateDeliveryPredFor(otherHost); - updateTransitivePreds(otherHost); - } - } - - /** - * Updates delivery predictions for a host. - * P(a,b) = P(a,b)_old + (1 - P(a,b)_old) * P_INIT - * @param host The host we just met - */ - private void updateDeliveryPredFor(DTNHost host) { - double oldValue = getPredFor(host); - double newValue = oldValue + (1 - oldValue) * P_INIT; - preds.put(host, newValue); - } - - /** - * Returns the current prediction (P) value for a host or 0 if entry for - * the host doesn't exist. - * @param host The host to look the P for - * @return the current P value - */ - public double getPredFor(DTNHost host) { - ageDeliveryPreds(); // make sure preds are updated before getting - if (preds.containsKey(host)) { - return preds.get(host); - } - else { - return 0; - } - } - - /** - * Updates transitive (A->B->C) delivery predictions. - * P(a,c) = P(a,c)_old + (1 - P(a,c)_old) * P(a,b) * P(b,c) * BETA - * - * @param host The B host who we just met - */ - private void updateTransitivePreds(DTNHost host) { - MessageRouter otherRouter = host.getRouter(); - assert otherRouter instanceof ProphetRouter : "PRoPHET only works " + - " with other routers of same type"; - - double pForHost = getPredFor(host); // P(a,b) - Map othersPreds = - ((ProphetRouter)otherRouter).getDeliveryPreds(); - - for (Map.Entry e : othersPreds.entrySet()) { - if (e.getKey() == getHost()) { - continue; // don't add yourself - } - - double pOld = getPredFor(e.getKey()); // P(a,c)_old - double pNew = pOld + ( 1 - pOld) * pForHost * e.getValue() * beta; - preds.put(e.getKey(), pNew); - } - } - - /** - * Ages all entries in the delivery predictions. - * P(a,b) = P(a,b)_old * (GAMMA ^ k), where k is number of - * time units that have elapsed since the last time the metric was aged. - * @see #SECONDS_IN_UNIT_S - */ - private void ageDeliveryPreds() { - double timeDiff = (SimClock.getTime() - this.lastAgeUpdate) / - secondsInTimeUnit; - - if (timeDiff == 0) { - return; - } - - double mult = Math.pow(GAMMA, timeDiff); - for (Map.Entry e : preds.entrySet()) { - e.setValue(e.getValue()*mult); - } - - this.lastAgeUpdate = SimClock.getTime(); - } - - /** - * Returns a map of this router's delivery predictions - * @return a map of this router's delivery predictions - */ - private Map getDeliveryPreds() { - ageDeliveryPreds(); // make sure the aging is done - return this.preds; - } - - @Override - public void update() { - super.update(); - if (!canStartTransfer() ||isTransferring()) { - return; // nothing to transfer or is currently transferring - } - - // try messages that could be delivered to final recipient - if (exchangeDeliverableMessages() != null) { - return; - } - - tryOtherMessages(); - } - - /** - * Tries to send all other messages to all connected hosts ordered by - * their delivery probability - * @return The return value of {@link #tryMessagesForConnected(List)} - */ - private Tuple tryOtherMessages() { - List> messages = - new ArrayList>(); - - Collection msgCollection = getMessageCollection(); - - /* for all connected hosts collect all messages that have a higher - probability of delivery by the other host */ - for (Connection con : getConnections()) { - DTNHost other = con.getOtherNode(getHost()); - ProphetRouter othRouter = (ProphetRouter)other.getRouter(); - - if (othRouter.isTransferring()) { - continue; // skip hosts that are transferring - } - - for (Message m : msgCollection) { - if (othRouter.hasMessage(m.getId())) { - continue; // skip messages that the other one has - } - if (othRouter.getPredFor(m.getTo()) > getPredFor(m.getTo())) { - // the other node has higher probability of delivery - messages.add(new Tuple(m,con)); - } - } - } - - if (messages.size() == 0) { - return null; - } - - // sort the message-connection tuples - Collections.sort(messages, new TupleComparator()); - return tryMessagesForConnected(messages); // try to send messages - } - - /** - * Comparator for Message-Connection-Tuples that orders the tuples by - * their delivery probability by the host on the other side of the - * connection (GRTRMax) - */ - private class TupleComparator implements Comparator - > { - - public int compare(Tuple tuple1, - Tuple tuple2) { - // delivery probability of tuple1's message with tuple1's connection - double p1 = ((ProphetRouter)tuple1.getValue(). - getOtherNode(getHost()).getRouter()).getPredFor( - tuple1.getKey().getTo()); - // -"- tuple2... - double p2 = ((ProphetRouter)tuple2.getValue(). - getOtherNode(getHost()).getRouter()).getPredFor( - tuple2.getKey().getTo()); - - // bigger probability should come first + + if (con.isUp()) { + DTNHost otherHost = con.getOtherNode(getHost()); + updateDeliveryPredFor(otherHost); + updateTransitivePreds(otherHost); + } + } + + /** + * Updates delivery predictions for a host. + * P(a,b) = P(a,b)_old + (1 - P(a,b)_old) * P_INIT + * @param host The host we just met + */ + private void updateDeliveryPredFor(DTNHost host) { + double oldValue = getPredFor(host); + double newValue = oldValue + (1 - oldValue) * P_INIT; + preds.put(host, newValue); + } + + /** + * Returns the current prediction (P) value for a host or 0 if entry for + * the host doesn't exist. + * @param host The host to look the P for + * @return the current P value + */ + public double getPredFor(DTNHost host) { + ageDeliveryPreds(); // make sure preds are updated before getting + if (preds.containsKey(host)) { + return preds.get(host); + } + else { + return 0; + } + } + + /** + * Updates transitive (A->B->C) delivery predictions. + * P(a,c) = P(a,c)_old + (1 - P(a,c)_old) * P(a,b) * P(b,c) * BETA + * + * @param host The B host who we just met + */ + private void updateTransitivePreds(DTNHost host) { + MessageRouter otherRouter = host.getRouter(); + assert otherRouter instanceof ProphetRouter : "PRoPHET only works " + + " with other routers of same type"; + + double pForHost = getPredFor(host); // P(a,b) + Map othersPreds = + ((ProphetRouter)otherRouter).getDeliveryPreds(); + + for (Map.Entry e : othersPreds.entrySet()) { + if (e.getKey() == getHost()) { + continue; // don't add yourself + } + + double pOld = getPredFor(e.getKey()); // P(a,c)_old + double pNew = pOld + ( 1 - pOld) * pForHost * e.getValue() * beta; + preds.put(e.getKey(), pNew); + } + } + + /** + * Ages all entries in the delivery predictions. + * P(a,b) = P(a,b)_old * (GAMMA ^ k), where k is number of + * time units that have elapsed since the last time the metric was aged. + * @see #SECONDS_IN_UNIT_S + */ + private void ageDeliveryPreds() { + double timeDiff = (SimClock.getTime() - this.lastAgeUpdate) / + secondsInTimeUnit; + + if (timeDiff == 0) { + return; + } + + double mult = Math.pow(GAMMA, timeDiff); + for (Map.Entry e : preds.entrySet()) { + e.setValue(e.getValue()*mult); + } + + this.lastAgeUpdate = SimClock.getTime(); + } + + /** + * Returns a map of this router's delivery predictions + * @return a map of this router's delivery predictions + */ + private Map getDeliveryPreds() { + ageDeliveryPreds(); // make sure the aging is done + return this.preds; + } + + @Override + public void update() { + super.update(); + if (!canStartTransfer() ||isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + // try messages that could be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; + } + + tryOtherMessages(); + } + + /** + * Tries to send all other messages to all connected hosts ordered by + * their delivery probability + * @return The return value of {@link #tryMessagesForConnected(List)} + */ + private Tuple tryOtherMessages() { + List> messages = + new ArrayList>(); + + Collection msgCollection = getMessageCollection(); + + /* for all connected hosts collect all messages that have a higher + probability of delivery by the other host */ + for (Connection con : getConnections()) { + DTNHost other = con.getOtherNode(getHost()); + ProphetRouter othRouter = (ProphetRouter)other.getRouter(); + + if (othRouter.isTransferring()) { + continue; // skip hosts that are transferring + } + + for (Message m : msgCollection) { + if (othRouter.hasMessage(m.getId())) { + continue; // skip messages that the other one has + } + if (othRouter.getPredFor(m.getTo()) > getPredFor(m.getTo())) { + // the other node has higher probability of delivery + messages.add(new Tuple(m,con)); + } + } + } + + if (messages.size() == 0) { + return null; + } + + // sort the message-connection tuples + Collections.sort(messages, new TupleComparator()); + return tryMessagesForConnected(messages); // try to send messages + } + + /** + * Comparator for Message-Connection-Tuples that orders the tuples by + * their delivery probability by the host on the other side of the + * connection (GRTRMax) + */ + private class TupleComparator implements Comparator + > { + + public int compare(Tuple tuple1, + Tuple tuple2) { + // delivery probability of tuple1's message with tuple1's connection + double p1 = ((ProphetRouter)tuple1.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple1.getKey().getTo()); + // -"- tuple2... + double p2 = ((ProphetRouter)tuple2.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple2.getKey().getTo()); + + // bigger probability should come first if (p2-p1 == 0) { - /* equal probabilities -> let queue mode decide */ - return compareByQueueMode(tuple1.getKey(), tuple2.getKey()); - } - else if (p2-p1 < 0) { - return -1; - } - else { - return 1; - } - } - } - - @Override - public RoutingInfo getRoutingInfo() { - ageDeliveryPreds(); - RoutingInfo top = super.getRoutingInfo(); - RoutingInfo ri = new RoutingInfo(preds.size() + - " delivery prediction(s)"); - - for (Map.Entry e : preds.entrySet()) { - DTNHost host = e.getKey(); - Double value = e.getValue(); - - ri.addMoreInfo(new RoutingInfo(String.format("%s : %.6f", - host, value))); - } - - top.addMoreInfo(ri); - return top; - } - - @Override - public MessageRouter replicate() { - ProphetRouter r = new ProphetRouter(this); - return r; - } - -} + /* equal probabilities -> let queue mode decide */ + return compareByQueueMode(tuple1.getKey(), tuple2.getKey()); + } + else if (p2-p1 < 0) { + return -1; + } + else { + return 1; + } + } + } + + @Override + public RoutingInfo getRoutingInfo() { + ageDeliveryPreds(); + RoutingInfo top = super.getRoutingInfo(); + RoutingInfo ri = new RoutingInfo(preds.size() + + " delivery prediction(s)"); + + for (Map.Entry e : preds.entrySet()) { + DTNHost host = e.getKey(); + Double value = e.getValue(); + + ri.addMoreInfo(new RoutingInfo(String.format("%s : %.6f", + host, value))); + } + + top.addMoreInfo(ri); + return top; + } + + @Override + public MessageRouter replicate() { + ProphetRouter r = new ProphetRouter(this); + return r; + } + +} diff --git a/routing/ProphetRouterWithEstimation.java b/routing/ProphetRouterWithEstimation.java index 75c75984a..41a524b26 100644 --- a/routing/ProphetRouterWithEstimation.java +++ b/routing/ProphetRouterWithEstimation.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; - +package routing; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -21,112 +21,112 @@ import core.Message; import core.Settings; import core.SimClock; - -/** - * Implementation of PRoPHET router as described in - * Probabilistic routing in intermittently connected networks by + +/** + * Implementation of PRoPHET router as described in + * Probabilistic routing in intermittently connected networks by * Anders Lindgren et al. - * - * + * + * * This version tries to estimate a good value of protocol parameters from * a timescale parameter given by the user, and from the encounters the node * sees during simulation. - * Refer to Karvo and Ott, Time Scales and Delay-Tolerant Routing - * Protocols Chants, 2008 - * - */ -public class ProphetRouterWithEstimation extends ActiveRouter { - /** delivery predictability initialization constant*/ - public static final double P_INIT = 0.75; - /** delivery predictability transitivity scaling constant default value */ - public static final double DEFAULT_BETA = 0.25; - /** delivery predictability aging constant */ - public static final double GAMMA = 0.98; + * Refer to Karvo and Ott, Time Scales and Delay-Tolerant Routing + * Protocols Chants, 2008 + * + */ +public class ProphetRouterWithEstimation extends ActiveRouter { + /** delivery predictability initialization constant*/ + public static final double P_INIT = 0.75; + /** delivery predictability transitivity scaling constant default value */ + public static final double DEFAULT_BETA = 0.25; + /** delivery predictability aging constant */ + public static final double GAMMA = 0.98; /** default P target */ public static final double DEFAULT_PTARGET = .2; - - /** Prophet router's setting namespace ({@value})*/ - public static final String PROPHET_NS = "ProphetRouterWithEstimation"; - /** - * Number of seconds in time scale.*/ - public static final String TIME_SCALE_S ="timeScale"; + + /** Prophet router's setting namespace ({@value})*/ + public static final String PROPHET_NS = "ProphetRouterWithEstimation"; + /** + * Number of seconds in time scale.*/ + public static final String TIME_SCALE_S ="timeScale"; /** * Target P_avg - * + * */ public static final String P_AVG_TARGET_S = "targetPavg"; - - /** - * Transitivity scaling constant (beta) -setting id ({@value}). - * Default value for setting is {@link #DEFAULT_BETA}. - */ - public static final String BETA_S = "beta"; - - /** values of parameter settings */ - private double beta; + + /** + * Transitivity scaling constant (beta) -setting id ({@value}). + * Default value for setting is {@link #DEFAULT_BETA}. + */ + public static final String BETA_S = "beta"; + + /** values of parameter settings */ + private double beta; private double gamma; private double pinit; /** value of time scale variable */ private int timescale; private double ptavg; - - /** delivery predictabilities */ + + /** delivery predictabilities */ private Map preds; /** last meeting time with a node */ private Map meetings; private int nrofSamples; private double meanIET; - - /** last delivery predictability update (sim)time */ - private double lastAgeUpdate; - - - /** - * Constructor. Creates a new message router based on the settings in - * the given Settings object. - * @param s The settings object - */ - public ProphetRouterWithEstimation(Settings s) { - super(s); - Settings prophetSettings = new Settings(PROPHET_NS); + + /** last delivery predictability update (sim)time */ + private double lastAgeUpdate; + + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public ProphetRouterWithEstimation(Settings s) { + super(s); + Settings prophetSettings = new Settings(PROPHET_NS); timescale = prophetSettings.getInt(TIME_SCALE_S); if (prophetSettings.contains(P_AVG_TARGET_S)) { ptavg = prophetSettings.getDouble(P_AVG_TARGET_S); } else { ptavg = DEFAULT_PTARGET; - } - if (prophetSettings.contains(BETA_S)) { - beta = prophetSettings.getDouble(BETA_S); - } else { - beta = DEFAULT_BETA; + } + if (prophetSettings.contains(BETA_S)) { + beta = prophetSettings.getDouble(BETA_S); + } else { + beta = DEFAULT_BETA; } gamma = GAMMA; - pinit = P_INIT; - + pinit = P_INIT; + initPreds(); - initMeetings(); - } - - /** - * Copyconstructor. - * @param r The router prototype where setting values are copied from - */ - protected ProphetRouterWithEstimation(ProphetRouterWithEstimation r) { - super(r); + initMeetings(); + } + + /** + * Copyconstructor. + * @param r The router prototype where setting values are copied from + */ + protected ProphetRouterWithEstimation(ProphetRouterWithEstimation r) { + super(r); this.timescale = r.timescale; - this.ptavg = r.ptavg; - this.beta = r.beta; + this.ptavg = r.ptavg; + this.beta = r.beta; initPreds(); - initMeetings(); - } - - /** - * Initializes predictability hash - */ - private void initPreds() { - this.preds = new HashMap(); + initMeetings(); + } + + /** + * Initializes predictability hash + */ + private void initPreds() { + this.preds = new HashMap(); } /** @@ -136,27 +136,27 @@ private void initMeetings() { this.meetings = new HashMap(); this.meanIET = 0; this.nrofSamples = 0; - } - - @Override + } + + @Override public void changedConnection(Connection con) { super.changedConnection(con); - - if (con.isUp()) { + + if (con.isUp()) { DTNHost otherHost = con.getOtherNode(getHost()); if (updateIET(otherHost)) { updateParams(); - } - updateDeliveryPredFor(otherHost); - updateTransitivePreds(otherHost); - } - } + } + updateDeliveryPredFor(otherHost); + updateTransitivePreds(otherHost); + } + } /** * Updates the interencounter time estimates * @param host */ - private boolean updateIET(DTNHost host) { + private boolean updateIET(DTNHost host) { /* First estimate the mean InterEncounter Time */ double currentTime = SimClock.getTime(); if (meetings.containsKey(host)) { @@ -172,7 +172,7 @@ private boolean updateIET(DTNHost host) { /* nothing to update */ meetings.put(host,currentTime); return false; - } + } } /** @@ -189,7 +189,7 @@ private void updateParams() double zetadiff; int ozeta; double pstable; - double pavg; + double pavg; double ee; double bdiff; int ob; @@ -212,7 +212,7 @@ private void updateParams() if (meanIET == 0) { System.out.printf("Mean IET == 0\n"); return; - } + } System.out.printf("prophetfindparams(%d,%f,%f);\n",timescale,ptavg,meanIET); b = 1e-5; @@ -263,7 +263,7 @@ private void updateParams() //System.out.printf("Zeta: %f Zetadiff: %f\n",zeta,zetadiff); ee = 1; - bdiff = .1; + bdiff = .1; ob = 0; zcount = 0; // if 100 iterations won't help, lets increase zeta... bcheck = false; @@ -318,206 +318,206 @@ private void updateParams() gamma = Math.exp(-b); pinit = 1-zeta; } - - /** - * Updates delivery predictions for a host. - * P(a,b) = P(a,b)_old + (1 - P(a,b)_old) * P_INIT - * @param host The host we just met - */ - private void updateDeliveryPredFor(DTNHost host) { - double oldValue = getPredFor(host); - double newValue = oldValue + (1 - oldValue) * pinit; - preds.put(host, newValue); - } - - /** - * Returns the current prediction (P) value for a host or 0 if entry for - * the host doesn't exist. - * @param host The host to look the P for - * @return the current P value - */ - public double getPredFor(DTNHost host) { - ageDeliveryPreds(); // make sure preds are updated before getting - if (preds.containsKey(host)) { - return preds.get(host); - } - else { - return 0; - } - } - - /** - * Updates transitive (A->B->C) delivery predictions. - * P(a,c) = P(a,c)_old + (1 - P(a,c)_old) * P(a,b) * P(b,c) * BETA - * - * @param host The B host who we just met - */ - private void updateTransitivePreds(DTNHost host) { - MessageRouter otherRouter = host.getRouter(); - assert otherRouter instanceof ProphetRouterWithEstimation : "PRoPHET only works " + - " with other routers of same type"; - - double pForHost = getPredFor(host); // P(a,b) - Map othersPreds = - ((ProphetRouterWithEstimation)otherRouter).getDeliveryPreds(); - - for (Map.Entry e : othersPreds.entrySet()) { - if (e.getKey() == getHost()) { - continue; // don't add yourself - } - - double pOld = getPredFor(e.getKey()); // P(a,c)_old - double pNew = pOld + ( 1 - pOld) * pForHost * e.getValue() * beta; - preds.put(e.getKey(), pNew); - } - } - - /** - * Ages all entries in the delivery predictions. - * P(a,b) = P(a,b)_old * (GAMMA ^ k), where k is number of - * time units that have elapsed since the last time the metric was aged. - * @see #SECONDS_IN_UNIT_S - */ - private void ageDeliveryPreds() { - double timeDiff = (SimClock.getTime() - this.lastAgeUpdate); - - if (timeDiff == 0) { - return; - } - - double mult = Math.pow(gamma, timeDiff); - for (Map.Entry e : preds.entrySet()) { - e.setValue(e.getValue()*mult); - } - - this.lastAgeUpdate = SimClock.getTime(); - } - - /** - * Returns a map of this router's delivery predictions - * @return a map of this router's delivery predictions - */ - private Map getDeliveryPreds() { - ageDeliveryPreds(); // make sure the aging is done - return this.preds; - } - - @Override - public void update() { - super.update(); - if (!canStartTransfer() ||isTransferring()) { - return; // nothing to transfer or is currently transferring - } - - // try messages that could be delivered to final recipient - if (exchangeDeliverableMessages() != null) { - return; - } - - tryOtherMessages(); - } - - /** - * Tries to send all other messages to all connected hosts ordered by - * their delivery probability - * @return The return value of {@link #tryMessagesForConnected(List)} - */ - private Tuple tryOtherMessages() { - List> messages = - new ArrayList>(); - - Collection msgCollection = getMessageCollection(); - - /* for all connected hosts collect all messages that have a higher - probability of delivery by the other host */ - for (Connection con : getConnections()) { - DTNHost other = con.getOtherNode(getHost()); - ProphetRouterWithEstimation othRouter = (ProphetRouterWithEstimation)other.getRouter(); - - if (othRouter.isTransferring()) { - continue; // skip hosts that are transferring - } - - for (Message m : msgCollection) { - if (othRouter.hasMessage(m.getId())) { - continue; // skip messages that the other one has - } - if (othRouter.getPredFor(m.getTo()) > getPredFor(m.getTo())) { - // the other node has higher probability of delivery - messages.add(new Tuple(m,con)); - } - } - } - - if (messages.size() == 0) { - return null; - } - - // sort the message-connection tuples - Collections.sort(messages, new TupleComparator()); - return tryMessagesForConnected(messages); // try to send messages - } - - /** - * Comparator for Message-Connection-Tuples that orders the tuples by - * their delivery probability by the host on the other side of the - * connection (GRTRMax) - */ - private class TupleComparator implements Comparator - > { - - public int compare(Tuple tuple1, - Tuple tuple2) { - // delivery probability of tuple1's message with tuple1's connection - double p1 = ((ProphetRouterWithEstimation)tuple1.getValue(). - getOtherNode(getHost()).getRouter()).getPredFor( - tuple1.getKey().getTo()); - // -"- tuple2... - double p2 = ((ProphetRouterWithEstimation)tuple2.getValue(). - getOtherNode(getHost()).getRouter()).getPredFor( - tuple2.getKey().getTo()); - - // bigger probability should come first + + /** + * Updates delivery predictions for a host. + * P(a,b) = P(a,b)_old + (1 - P(a,b)_old) * P_INIT + * @param host The host we just met + */ + private void updateDeliveryPredFor(DTNHost host) { + double oldValue = getPredFor(host); + double newValue = oldValue + (1 - oldValue) * pinit; + preds.put(host, newValue); + } + + /** + * Returns the current prediction (P) value for a host or 0 if entry for + * the host doesn't exist. + * @param host The host to look the P for + * @return the current P value + */ + public double getPredFor(DTNHost host) { + ageDeliveryPreds(); // make sure preds are updated before getting + if (preds.containsKey(host)) { + return preds.get(host); + } + else { + return 0; + } + } + + /** + * Updates transitive (A->B->C) delivery predictions. + * P(a,c) = P(a,c)_old + (1 - P(a,c)_old) * P(a,b) * P(b,c) * BETA + * + * @param host The B host who we just met + */ + private void updateTransitivePreds(DTNHost host) { + MessageRouter otherRouter = host.getRouter(); + assert otherRouter instanceof ProphetRouterWithEstimation : "PRoPHET only works " + + " with other routers of same type"; + + double pForHost = getPredFor(host); // P(a,b) + Map othersPreds = + ((ProphetRouterWithEstimation)otherRouter).getDeliveryPreds(); + + for (Map.Entry e : othersPreds.entrySet()) { + if (e.getKey() == getHost()) { + continue; // don't add yourself + } + + double pOld = getPredFor(e.getKey()); // P(a,c)_old + double pNew = pOld + ( 1 - pOld) * pForHost * e.getValue() * beta; + preds.put(e.getKey(), pNew); + } + } + + /** + * Ages all entries in the delivery predictions. + * P(a,b) = P(a,b)_old * (GAMMA ^ k), where k is number of + * time units that have elapsed since the last time the metric was aged. + * @see #SECONDS_IN_UNIT_S + */ + private void ageDeliveryPreds() { + double timeDiff = (SimClock.getTime() - this.lastAgeUpdate); + + if (timeDiff == 0) { + return; + } + + double mult = Math.pow(gamma, timeDiff); + for (Map.Entry e : preds.entrySet()) { + e.setValue(e.getValue()*mult); + } + + this.lastAgeUpdate = SimClock.getTime(); + } + + /** + * Returns a map of this router's delivery predictions + * @return a map of this router's delivery predictions + */ + private Map getDeliveryPreds() { + ageDeliveryPreds(); // make sure the aging is done + return this.preds; + } + + @Override + public void update() { + super.update(); + if (!canStartTransfer() ||isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + // try messages that could be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; + } + + tryOtherMessages(); + } + + /** + * Tries to send all other messages to all connected hosts ordered by + * their delivery probability + * @return The return value of {@link #tryMessagesForConnected(List)} + */ + private Tuple tryOtherMessages() { + List> messages = + new ArrayList>(); + + Collection msgCollection = getMessageCollection(); + + /* for all connected hosts collect all messages that have a higher + probability of delivery by the other host */ + for (Connection con : getConnections()) { + DTNHost other = con.getOtherNode(getHost()); + ProphetRouterWithEstimation othRouter = (ProphetRouterWithEstimation)other.getRouter(); + + if (othRouter.isTransferring()) { + continue; // skip hosts that are transferring + } + + for (Message m : msgCollection) { + if (othRouter.hasMessage(m.getId())) { + continue; // skip messages that the other one has + } + if (othRouter.getPredFor(m.getTo()) > getPredFor(m.getTo())) { + // the other node has higher probability of delivery + messages.add(new Tuple(m,con)); + } + } + } + + if (messages.size() == 0) { + return null; + } + + // sort the message-connection tuples + Collections.sort(messages, new TupleComparator()); + return tryMessagesForConnected(messages); // try to send messages + } + + /** + * Comparator for Message-Connection-Tuples that orders the tuples by + * their delivery probability by the host on the other side of the + * connection (GRTRMax) + */ + private class TupleComparator implements Comparator + > { + + public int compare(Tuple tuple1, + Tuple tuple2) { + // delivery probability of tuple1's message with tuple1's connection + double p1 = ((ProphetRouterWithEstimation)tuple1.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple1.getKey().getTo()); + // -"- tuple2... + double p2 = ((ProphetRouterWithEstimation)tuple2.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple2.getKey().getTo()); + + // bigger probability should come first if (p2-p1 == 0) { - /* equal probabilities -> let queue mode decide */ - return compareByQueueMode(tuple1.getKey(), tuple2.getKey()); - } - else if (p2-p1 < 0) { - return -1; - } - else { - return 1; - } - } - } - - @Override - public RoutingInfo getRoutingInfo() { - ageDeliveryPreds(); - RoutingInfo top = super.getRoutingInfo(); - RoutingInfo ri = new RoutingInfo(preds.size() + - " delivery prediction(s)"); - - for (Map.Entry e : preds.entrySet()) { - DTNHost host = e.getKey(); - Double value = e.getValue(); - - ri.addMoreInfo(new RoutingInfo(String.format("%s : %.6f", - host, value))); - } + /* equal probabilities -> let queue mode decide */ + return compareByQueueMode(tuple1.getKey(), tuple2.getKey()); + } + else if (p2-p1 < 0) { + return -1; + } + else { + return 1; + } + } + } + + @Override + public RoutingInfo getRoutingInfo() { + ageDeliveryPreds(); + RoutingInfo top = super.getRoutingInfo(); + RoutingInfo ri = new RoutingInfo(preds.size() + + " delivery prediction(s)"); + + for (Map.Entry e : preds.entrySet()) { + DTNHost host = e.getKey(); + Double value = e.getValue(); + + ri.addMoreInfo(new RoutingInfo(String.format("%s : %.6f", + host, value))); + } ri.addMoreInfo(new RoutingInfo(String.format("meanIET: %f\t from %d samples",meanIET,nrofSamples))); ri.addMoreInfo(new RoutingInfo(String.format("current gamma: %f",gamma))); ri.addMoreInfo(new RoutingInfo(String.format("current Pinit: %f",pinit))); - - top.addMoreInfo(ri); - return top; - } - - @Override - public MessageRouter replicate() { - ProphetRouterWithEstimation r = new ProphetRouterWithEstimation(this); - return r; - } - -} + + top.addMoreInfo(ri); + return top; + } + + @Override + public MessageRouter replicate() { + ProphetRouterWithEstimation r = new ProphetRouterWithEstimation(this); + return r; + } + +} diff --git a/routing/ProphetV2Router.java b/routing/ProphetV2Router.java index 757debab0..ce3d9a8fd 100644 --- a/routing/ProphetV2Router.java +++ b/routing/ProphetV2Router.java @@ -1,113 +1,113 @@ -/* +/* * Copyright 2011 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - * The Original PRoPHET code updated to PRoPHETv2 router + * Released under GPLv3. See LICENSE.txt for details. + * The Original PRoPHET code updated to PRoPHETv2 router * by Samo Grasic(samo@grasic.net) - Jun 2011 */ -package routing; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; +package routing; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Random; import routing.util.RoutingInfo; - - -import core.Connection; -import core.DTNHost; -import core.Message; -import core.Settings; -import core.SimClock; -import util.Tuple; - -/** - * Implementation of PRoPHETv2" router as described in - * http://tools.ietf.org/html/draft-irtf-dtnrg-prophet-09 - */ -public class ProphetV2Router extends ActiveRouter { - /** delivery predictability initialization constant*/ - public static final double PEncMax = 0.5; + + +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; +import core.SimClock; +import util.Tuple; + +/** + * Implementation of PRoPHETv2" router as described in + * http://tools.ietf.org/html/draft-irtf-dtnrg-prophet-09 + */ +public class ProphetV2Router extends ActiveRouter { + /** delivery predictability initialization constant*/ + public static final double PEncMax = 0.5; /** typical interconnection time in seconds*/ - public static final double I_TYP = 1800; - /** delivery predictability transitivity scaling constant default value */ - public static final double DEFAULT_BETA = 0.9; - /** delivery predictability aging constant */ - public static final double GAMMA = 0.999885791; + public static final double I_TYP = 1800; + /** delivery predictability transitivity scaling constant default value */ + public static final double DEFAULT_BETA = 0.9; + /** delivery predictability aging constant */ + public static final double GAMMA = 0.999885791; Random randomGenerator = new Random(); - - /** Prophet router's setting namespace ({@value})*/ - public static final String PROPHET_NS = "ProphetV2Router"; - /** - * Number of seconds in time unit -setting id ({@value}). - * How many seconds one time unit is when calculating aging of - * delivery predictions. Should be tweaked for the scenario.*/ - public static final String SECONDS_IN_UNIT_S ="secondsInTimeUnit"; - - /** - * Transitivity scaling constant (beta) -setting id ({@value}). - * Default value for setting is {@link #DEFAULT_BETA}. - */ - public static final String BETA_S = "beta"; - - /** the value of nrof seconds in time unit -setting */ - private int secondsInTimeUnit; - /** value of beta setting */ - private double beta; - - /** delivery predictabilities */ - private Map preds; + + /** Prophet router's setting namespace ({@value})*/ + public static final String PROPHET_NS = "ProphetV2Router"; + /** + * Number of seconds in time unit -setting id ({@value}). + * How many seconds one time unit is when calculating aging of + * delivery predictions. Should be tweaked for the scenario.*/ + public static final String SECONDS_IN_UNIT_S ="secondsInTimeUnit"; + + /** + * Transitivity scaling constant (beta) -setting id ({@value}). + * Default value for setting is {@link #DEFAULT_BETA}. + */ + public static final String BETA_S = "beta"; + + /** the value of nrof seconds in time unit -setting */ + private int secondsInTimeUnit; + /** value of beta setting */ + private double beta; + + /** delivery predictabilities */ + private Map preds; /** last encouter timestamp (sim)time */ private Map lastEncouterTime; - - /** last delivery predictability update (sim)time */ - private double lastAgeUpdate; - - /** - * Constructor. Creates a new message router based on the settings in - * the given Settings object. - * @param s The settings object - */ - public ProphetV2Router(Settings s) { - super(s); - Settings prophetSettings = new Settings(PROPHET_NS); - secondsInTimeUnit = prophetSettings.getInt(SECONDS_IN_UNIT_S); - if (prophetSettings.contains(BETA_S)) { - beta = prophetSettings.getDouble(BETA_S); - } - else { - beta = DEFAULT_BETA; - } - + + /** last delivery predictability update (sim)time */ + private double lastAgeUpdate; + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public ProphetV2Router(Settings s) { + super(s); + Settings prophetSettings = new Settings(PROPHET_NS); + secondsInTimeUnit = prophetSettings.getInt(SECONDS_IN_UNIT_S); + if (prophetSettings.contains(BETA_S)) { + beta = prophetSettings.getDouble(BETA_S); + } + else { + beta = DEFAULT_BETA; + } + initPreds(); initEncTimes(); - - } - - /** - * Copyc onstructor. - * @param The router prototype where setting values are copied from - */ - protected ProphetV2Router(ProphetV2Router r) { - super(r); - this.secondsInTimeUnit = r.secondsInTimeUnit; - this.beta = r.beta; + + } + + /** + * Copyc onstructor. + * @param The router prototype where setting values are copied from + */ + protected ProphetV2Router(ProphetV2Router r) { + super(r); + this.secondsInTimeUnit = r.secondsInTimeUnit; + this.beta = r.beta; initPreds(); - initEncTimes(); - } - - /** - * Initializes lastEncouterTime hash - */ - private void initEncTimes() { - this.lastEncouterTime = new HashMap(); - } + initEncTimes(); + } + + /** + * Initializes lastEncouterTime hash + */ + private void initEncTimes() { + this.lastEncouterTime = new HashMap(); + } /** * Initializes predictability hash @@ -115,24 +115,24 @@ private void initEncTimes() { private void initPreds() { this.preds = new HashMap(); } - - @Override - public void changedConnection(Connection con) { - if (con.isUp()) { - DTNHost otherHost = con.getOtherNode(getHost()); - updateDeliveryPredFor(otherHost); + + @Override + public void changedConnection(Connection con) { + if (con.isUp()) { + DTNHost otherHost = con.getOtherNode(getHost()); + updateDeliveryPredFor(otherHost); updateTransitivePreds(otherHost); - } - } - - /** - * Updates delivery predictions for a host. + } + } + + /** + * Updates delivery predictions for a host. * P(a,b) = P(a,b)_old + (1 - P(a,b)_old) * PEnc * PEnc(intvl) = * P_encounter_max * (intvl / I_typ) for 0<= intvl <= I_typ - * P_encounter_max for intvl > I_typ - * @param host The host we just met - */ + * P_encounter_max for intvl > I_typ + * @param host The host we just met + */ private void updateDeliveryPredFor(DTNHost host) { double PEnc; double simTime = SimClock.getTime(); @@ -147,14 +147,14 @@ private void updateDeliveryPredFor(DTNHost host) { else PEnc=PEncMax; - double oldValue = getPredFor(host); + double oldValue = getPredFor(host); double newValue = oldValue + (1 - oldValue) * PEnc; preds.put(host, newValue); lastEncouterTime.put(host, simTime); - } - + } + /** - * Returns the timestamp of the last encouter of with the host or -1 if + * Returns the timestamp of the last encouter of with the host or -1 if * entry for the host doesn't exist. * @param host The host to look the timestamp for * @return the last timestamp of encouter with the host @@ -167,7 +167,7 @@ public double getEncTimeFor(DTNHost host) { return 0; } } - + /** * Returns the current prediction (P) value for a host or 0 if entry for * the host doesn't exist. @@ -182,180 +182,180 @@ public double getPredFor(DTNHost host) { else { return 0; } - } - - /** - * Updates transitive (A->B->C) delivery predictions. - * P(a,c) = P(a,c)_old + (1 - P(a,c)_old) * P(a,b) * P(b,c) * BETA - * - * @param host The B host who we just met - */ - private void updateTransitivePreds(DTNHost host) { - MessageRouter otherRouter = host.getRouter(); - assert otherRouter instanceof ProphetV2Router : - "PRoPHETv2 only works with other routers of same type"; - - double pForHost = getPredFor(host); // P(a,b) - Map othersPreds = - ((ProphetV2Router)otherRouter).getDeliveryPreds(); - - for (Map.Entry e : othersPreds.entrySet()) { - if (e.getKey() == getHost()) { - continue; // don't add yourself - } + } + + /** + * Updates transitive (A->B->C) delivery predictions. + * P(a,c) = P(a,c)_old + (1 - P(a,c)_old) * P(a,b) * P(b,c) * BETA + * + * @param host The B host who we just met + */ + private void updateTransitivePreds(DTNHost host) { + MessageRouter otherRouter = host.getRouter(); + assert otherRouter instanceof ProphetV2Router : + "PRoPHETv2 only works with other routers of same type"; + + double pForHost = getPredFor(host); // P(a,b) + Map othersPreds = + ((ProphetV2Router)otherRouter).getDeliveryPreds(); + + for (Map.Entry e : othersPreds.entrySet()) { + if (e.getKey() == getHost()) { + continue; // don't add yourself + } //ProphetV2 max(old,new) double pOld = getPredFor(e.getKey()); // P(a,c)_old double pNew = pForHost * e.getValue() * beta; if(pNew>pOld) preds.put(e.getKey(), pNew); - - } - } - - /** - * Ages all entries in the delivery predictions. - * P(a,b) = P(a,b)_old * (GAMMA ^ k), where k is number of - * time units that have elapsed since the last time the metric was aged. - * @see #SECONDS_IN_UNIT_S - */ - private void ageDeliveryPreds() { - double timeDiff = (SimClock.getTime() - this.lastAgeUpdate) / - secondsInTimeUnit; - - if (timeDiff == 0) { - return; - } - - double mult = Math.pow(GAMMA, timeDiff); - for (Map.Entry e : preds.entrySet()) { - e.setValue(e.getValue()*mult); - } - - this.lastAgeUpdate = SimClock.getTime(); - } - - /** - * Returns a map of this router's delivery predictions - * @return a map of this router's delivery predictions - */ - private Map getDeliveryPreds() { - ageDeliveryPreds(); // make sure the aging is done - return this.preds; - } - - @Override - public void update() { - super.update(); - if (!canStartTransfer() ||isTransferring()) { - return; // nothing to transfer or is currently transferring - } - - // try messages that could be delivered to final recipient - if (exchangeDeliverableMessages() != null) { - return; - } - - tryOtherMessages(); - } - - /** - * Tries to send all other messages to all connected hosts ordered by - * their delivery probability - * @return The return value of {@link #tryMessagesForConnected(List)} - */ - private Tuple tryOtherMessages() { - List> messages = - new ArrayList>(); - - Collection msgCollection = getMessageCollection(); - - /* for all connected hosts collect all messages that have a higher - probability of delivery by the other host */ - for (Connection con : getConnections()) { - DTNHost other = con.getOtherNode(getHost()); - ProphetV2Router othRouter = (ProphetV2Router)other.getRouter(); - - if (othRouter.isTransferring()) { - continue; // skip hosts that are transferring - } - - for (Message m : msgCollection) { - if (othRouter.hasMessage(m.getId())) { - continue; // skip messages that the other one has - } + + } + } + + /** + * Ages all entries in the delivery predictions. + * P(a,b) = P(a,b)_old * (GAMMA ^ k), where k is number of + * time units that have elapsed since the last time the metric was aged. + * @see #SECONDS_IN_UNIT_S + */ + private void ageDeliveryPreds() { + double timeDiff = (SimClock.getTime() - this.lastAgeUpdate) / + secondsInTimeUnit; + + if (timeDiff == 0) { + return; + } + + double mult = Math.pow(GAMMA, timeDiff); + for (Map.Entry e : preds.entrySet()) { + e.setValue(e.getValue()*mult); + } + + this.lastAgeUpdate = SimClock.getTime(); + } + + /** + * Returns a map of this router's delivery predictions + * @return a map of this router's delivery predictions + */ + private Map getDeliveryPreds() { + ageDeliveryPreds(); // make sure the aging is done + return this.preds; + } + + @Override + public void update() { + super.update(); + if (!canStartTransfer() ||isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + // try messages that could be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; + } + + tryOtherMessages(); + } + + /** + * Tries to send all other messages to all connected hosts ordered by + * their delivery probability + * @return The return value of {@link #tryMessagesForConnected(List)} + */ + private Tuple tryOtherMessages() { + List> messages = + new ArrayList>(); + + Collection msgCollection = getMessageCollection(); + + /* for all connected hosts collect all messages that have a higher + probability of delivery by the other host */ + for (Connection con : getConnections()) { + DTNHost other = con.getOtherNode(getHost()); + ProphetV2Router othRouter = (ProphetV2Router)other.getRouter(); + + if (othRouter.isTransferring()) { + continue; // skip hosts that are transferring + } + + for (Message m : msgCollection) { + if (othRouter.hasMessage(m.getId())) { + continue; // skip messages that the other one has + } if((othRouter.getPredFor(m.getTo()) >= getPredFor(m.getTo()))) { - - messages.add(new Tuple(m,con)); - } - } - } - - if (messages.size() == 0) { - return null; - } - - // sort the message-connection tuples - Collections.sort(messages, new TupleComparator()); - return tryMessagesForConnected(messages); // try to send messages - } - - /** - * Comparator for Message-Connection-Tuples that orders the tuples by - * their delivery probability by the host on the other side of the - * connection (GRTRMax) - */ - private class TupleComparator implements Comparator - > { - - public int compare(Tuple tuple1, - Tuple tuple2) { - // delivery probability of tuple1's message with tuple1's connection - double p1 = ((ProphetV2Router)tuple1.getValue(). - getOtherNode(getHost()).getRouter()).getPredFor( - tuple1.getKey().getTo()); - // -"- tuple2... - double p2 = ((ProphetV2Router)tuple2.getValue(). - getOtherNode(getHost()).getRouter()).getPredFor( - tuple2.getKey().getTo()); - - // bigger probability should come first + + messages.add(new Tuple(m,con)); + } + } + } + + if (messages.size() == 0) { + return null; + } + + // sort the message-connection tuples + Collections.sort(messages, new TupleComparator()); + return tryMessagesForConnected(messages); // try to send messages + } + + /** + * Comparator for Message-Connection-Tuples that orders the tuples by + * their delivery probability by the host on the other side of the + * connection (GRTRMax) + */ + private class TupleComparator implements Comparator + > { + + public int compare(Tuple tuple1, + Tuple tuple2) { + // delivery probability of tuple1's message with tuple1's connection + double p1 = ((ProphetV2Router)tuple1.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple1.getKey().getTo()); + // -"- tuple2... + double p2 = ((ProphetV2Router)tuple2.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple2.getKey().getTo()); + + // bigger probability should come first if (p2-p1 == 0) { - /* equal probabilities -> let queue mode decide */ - return compareByQueueMode(tuple1.getKey(), tuple2.getKey()); - } - else if (p2-p1 < 0) { - return -1; - } - else { - return 1; - } - } - } - - @Override - public RoutingInfo getRoutingInfo() { - ageDeliveryPreds(); - RoutingInfo top = super.getRoutingInfo(); - RoutingInfo ri = new RoutingInfo(preds.size() + - " delivery prediction(s)"); - - for (Map.Entry e : preds.entrySet()) { - DTNHost host = e.getKey(); - Double value = e.getValue(); - - ri.addMoreInfo(new RoutingInfo(String.format("%s : %.6f", - host, value))); - } - - top.addMoreInfo(ri); - return top; - } - - @Override - public MessageRouter replicate() { - ProphetV2Router r = new ProphetV2Router(this); - return r; - } -} \ No newline at end of file + /* equal probabilities -> let queue mode decide */ + return compareByQueueMode(tuple1.getKey(), tuple2.getKey()); + } + else if (p2-p1 < 0) { + return -1; + } + else { + return 1; + } + } + } + + @Override + public RoutingInfo getRoutingInfo() { + ageDeliveryPreds(); + RoutingInfo top = super.getRoutingInfo(); + RoutingInfo ri = new RoutingInfo(preds.size() + + " delivery prediction(s)"); + + for (Map.Entry e : preds.entrySet()) { + DTNHost host = e.getKey(); + Double value = e.getValue(); + + ri.addMoreInfo(new RoutingInfo(String.format("%s : %.6f", + host, value))); + } + + top.addMoreInfo(ri); + return top; + } + + @Override + public MessageRouter replicate() { + ProphetV2Router r = new ProphetV2Router(this); + return r; + } +} diff --git a/routing/SprayAndWaitRouter.java b/routing/SprayAndWaitRouter.java index 07103a561..566b02429 100644 --- a/routing/SprayAndWaitRouter.java +++ b/routing/SprayAndWaitRouter.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; - +package routing; + import java.util.ArrayList; import java.util.List; @@ -11,153 +11,153 @@ import core.DTNHost; import core.Message; import core.Settings; - -/** - * Implementation of Spray and wait router as depicted in - * Spray and Wait: An Efficient Routing Scheme for Intermittently - * Connected Mobile Networks by Thrasyvoulos Spyropoulus et al. - * - */ -public class SprayAndWaitRouter extends ActiveRouter { - /** identifier for the initial number of copies setting ({@value})*/ - public static final String NROF_COPIES = "nrofCopies"; - /** identifier for the binary-mode setting ({@value})*/ - public static final String BINARY_MODE = "binaryMode"; - /** SprayAndWait router's settings name space ({@value})*/ + +/** + * Implementation of Spray and wait router as depicted in + * Spray and Wait: An Efficient Routing Scheme for Intermittently + * Connected Mobile Networks by Thrasyvoulos Spyropoulus et al. + * + */ +public class SprayAndWaitRouter extends ActiveRouter { + /** identifier for the initial number of copies setting ({@value})*/ + public static final String NROF_COPIES = "nrofCopies"; + /** identifier for the binary-mode setting ({@value})*/ + public static final String BINARY_MODE = "binaryMode"; + /** SprayAndWait router's settings name space ({@value})*/ public static final String SPRAYANDWAIT_NS = "SprayAndWaitRouter"; /** Message property key */ public static final String MSG_COUNT_PROPERTY = SPRAYANDWAIT_NS + "." + - "copies"; - - protected int initialNrofCopies; - protected boolean isBinary; - - public SprayAndWaitRouter(Settings s) { - super(s); - Settings snwSettings = new Settings(SPRAYANDWAIT_NS); - - initialNrofCopies = snwSettings.getInt(NROF_COPIES); - isBinary = snwSettings.getBoolean( BINARY_MODE); - } - - /** - * Copy constructor. - * @param r The router prototype where setting values are copied from - */ - protected SprayAndWaitRouter(SprayAndWaitRouter r) { - super(r); - this.initialNrofCopies = r.initialNrofCopies; - this.isBinary = r.isBinary; - } - - @Override - public int receiveMessage(Message m, DTNHost from) { - return super.receiveMessage(m, from); - } - - @Override - public Message messageTransferred(String id, DTNHost from) { - Message msg = super.messageTransferred(id, from); + "copies"; + + protected int initialNrofCopies; + protected boolean isBinary; + + public SprayAndWaitRouter(Settings s) { + super(s); + Settings snwSettings = new Settings(SPRAYANDWAIT_NS); + + initialNrofCopies = snwSettings.getInt(NROF_COPIES); + isBinary = snwSettings.getBoolean( BINARY_MODE); + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected SprayAndWaitRouter(SprayAndWaitRouter r) { + super(r); + this.initialNrofCopies = r.initialNrofCopies; + this.isBinary = r.isBinary; + } + + @Override + public int receiveMessage(Message m, DTNHost from) { + return super.receiveMessage(m, from); + } + + @Override + public Message messageTransferred(String id, DTNHost from) { + Message msg = super.messageTransferred(id, from); Integer nrofCopies = (Integer)msg.getProperty(MSG_COUNT_PROPERTY); - + assert nrofCopies != null : "Not a SnW message: " + msg; - - if (isBinary) { - /* in binary S'n'W the receiving node gets ceil(n/2) copies */ - nrofCopies = (int)Math.ceil(nrofCopies/2.0); - } - else { - /* in standard S'n'W the receiving node gets only single copy */ - nrofCopies = 1; - } - - msg.updateProperty(MSG_COUNT_PROPERTY, nrofCopies); - return msg; - } - - @Override - public boolean createNewMessage(Message msg) { - makeRoomForNewMessage(msg.getSize()); - + + if (isBinary) { + /* in binary S'n'W the receiving node gets ceil(n/2) copies */ + nrofCopies = (int)Math.ceil(nrofCopies/2.0); + } + else { + /* in standard S'n'W the receiving node gets only single copy */ + nrofCopies = 1; + } + + msg.updateProperty(MSG_COUNT_PROPERTY, nrofCopies); + return msg; + } + + @Override + public boolean createNewMessage(Message msg) { + makeRoomForNewMessage(msg.getSize()); + msg.setTtl(this.msgTtl); msg.addProperty(MSG_COUNT_PROPERTY, new Integer(initialNrofCopies)); - addToMessages(msg, true); - return true; - } - - @Override - public void update() { - super.update(); - if (!canStartTransfer() || isTransferring()) { - return; // nothing to transfer or is currently transferring - } - - /* try messages that could be delivered to final recipient */ - if (exchangeDeliverableMessages() != null) { - return; - } - + addToMessages(msg, true); + return true; + } + + @Override + public void update() { + super.update(); + if (!canStartTransfer() || isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + /* try messages that could be delivered to final recipient */ + if (exchangeDeliverableMessages() != null) { + return; + } + /* create a list of SAWMessages that have copies left to distribute */ - @SuppressWarnings(value = "unchecked") - List copiesLeft = sortByQueueMode(getMessagesWithCopiesLeft()); - - if (copiesLeft.size() > 0) { - /* try to send those messages */ + @SuppressWarnings(value = "unchecked") + List copiesLeft = sortByQueueMode(getMessagesWithCopiesLeft()); + + if (copiesLeft.size() > 0) { + /* try to send those messages */ this.tryMessagesToConnections(copiesLeft, getConnections()); - } - } - - /** - * Creates and returns a list of messages this router is currently - * carrying and still has copies left to distribute (nrof copies > 1). - * @return A list of messages that have copies left - */ - protected List getMessagesWithCopiesLeft() { - List list = new ArrayList(); - + } + } + + /** + * Creates and returns a list of messages this router is currently + * carrying and still has copies left to distribute (nrof copies > 1). + * @return A list of messages that have copies left + */ + protected List getMessagesWithCopiesLeft() { + List list = new ArrayList(); + for (Message m : getMessageCollection()) { Integer nrofCopies = (Integer)m.getProperty(MSG_COUNT_PROPERTY); - assert nrofCopies != null : "SnW message " + m + " didn't have " + - "nrof copies property!"; - if (nrofCopies > 1) { - list.add(m); - } - } - - return list; - } - - /** - * Called just before a transfer is finalized (by - * {@link ActiveRouter#update()}). - * Reduces the number of copies we have left for a message. - * In binary Spray and Wait, sending host is left with floor(n/2) copies, - * but in standard mode, nrof copies left is reduced by one. - */ - @Override + assert nrofCopies != null : "SnW message " + m + " didn't have " + + "nrof copies property!"; + if (nrofCopies > 1) { + list.add(m); + } + } + + return list; + } + + /** + * Called just before a transfer is finalized (by + * {@link ActiveRouter#update()}). + * Reduces the number of copies we have left for a message. + * In binary Spray and Wait, sending host is left with floor(n/2) copies, + * but in standard mode, nrof copies left is reduced by one. + */ + @Override protected void transferDone(Connection con) { Integer nrofCopies; - String msgId = con.getMessage().getId(); - /* get this router's copy of the message */ - Message msg = getMessage(msgId); - - if (msg == null) { // message has been dropped from the buffer after.. - return; // ..start of transfer -> no need to reduce amount of copies - } - + String msgId = con.getMessage().getId(); + /* get this router's copy of the message */ + Message msg = getMessage(msgId); + + if (msg == null) { // message has been dropped from the buffer after.. + return; // ..start of transfer -> no need to reduce amount of copies + } + /* reduce the amount of copies left */ - nrofCopies = (Integer)msg.getProperty(MSG_COUNT_PROPERTY); - if (isBinary) { - nrofCopies /= 2; - } - else { - nrofCopies--; + nrofCopies = (Integer)msg.getProperty(MSG_COUNT_PROPERTY); + if (isBinary) { + nrofCopies /= 2; + } + else { + nrofCopies--; } - msg.updateProperty(MSG_COUNT_PROPERTY, nrofCopies); - } - - @Override - public SprayAndWaitRouter replicate() { - return new SprayAndWaitRouter(this); + msg.updateProperty(MSG_COUNT_PROPERTY, nrofCopies); + } + + @Override + public SprayAndWaitRouter replicate() { + return new SprayAndWaitRouter(this); } -} +} diff --git a/routing/WaveRouter.java b/routing/WaveRouter.java index 3854f67ae..db8246733 100644 --- a/routing/WaveRouter.java +++ b/routing/WaveRouter.java @@ -1,8 +1,8 @@ -/* +/* * Copyright 2011 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing; +package routing; import java.util.Collection; import java.util.HashMap; @@ -15,94 +15,94 @@ import core.Message; import core.Settings; import core.SimClock; - -/** + +/** * Epidemic-like message router making waves of messages. - * Work in progress. - */ + * Work in progress. + */ public class WaveRouter extends ActiveRouter { - - /** + + /** * Immunity time -setting id ({@value}). Defines how long time a node - * will reject incoming messages it has already received + * will reject incoming messages it has already received */ public static final String IMMUNITY_S = "immunityTime"; - /** + /** * Custody fraction -setting id ({@value}). Defines how long (compared to - * immunity time) nodes accept custody for new incoming messages. + * immunity time) nodes accept custody for new incoming messages. */ public static final String CUSTODY_S = "custodyFraction"; private double immunityTime; private double custodyFraction; /** map of recently received messages and their receive times */ - private Map recentMessages; + private Map recentMessages; /** IDs of the messages this host has custody for */ private Map custodyMessages; - - /** - * Constructor. Creates a new message router based on the settings in - * the given Settings object. - * @param s The settings object - */ - public WaveRouter(Settings s) { + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public WaveRouter(Settings s) { super(s); this.immunityTime = s.getDouble(IMMUNITY_S); - this.custodyFraction = s.getDouble(CUSTODY_S); - } - - /** - * Copy constructor. - * @param r The router prototype where setting values are copied from - */ - protected WaveRouter(WaveRouter r) { - super(r); + this.custodyFraction = s.getDouble(CUSTODY_S); + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected WaveRouter(WaveRouter r) { + super(r); recentMessages = new HashMap(); this.immunityTime = r.immunityTime; this.custodyFraction = r.custodyFraction; - this.custodyMessages = new HashMap(); - } + this.custodyMessages = new HashMap(); + } @Override protected int checkReceiving(Message m, DTNHost from) { Double lastTime = this.recentMessages.get(m.getId()); - + if (lastTime != null) { if (lastTime + this.immunityTime > SimClock.getTime()) { return DENIED_POLICY; /* still immune to the message */ } else { /* immunity has passed; remove from recent */ - this.recentMessages.remove(m.getId()); + this.recentMessages.remove(m.getId()); } } /* no last time or immunity passed; receive based on other checks */ return super.checkReceiving(m, from); } - + /** - * Returns the oldest message that has been already sent forward + * Returns the oldest message that has been already sent forward */ @Override protected Message getNextMessageToRemove(boolean excludeMsgBeingSent) { Collection messages = this.getMessageCollection(); Message oldest = null; - + for (Message m : messages) { Double custodyStartTime = this.custodyMessages.get(m.getId()); if (custodyStartTime != null) { - if (SimClock.getTime() > + if (SimClock.getTime() > custodyStartTime + immunityTime * custodyFraction) { this.custodyMessages.remove(m.getId()); /* time passed */ } else { - continue; /* skip messages that still have custody */ + continue; /* skip messages that still have custody */ } } - - + + if (excludeMsgBeingSent && isSending(m.getId())) { continue; /* skip the message(s) that router is sending */ } - + if (oldest == null ) { oldest = m; } @@ -110,25 +110,25 @@ else if (oldest.getReceiveTime() > m.getReceiveTime()) { oldest = m; } } - + return oldest; } - - @Override - public void update() { + + @Override + public void update() { super.update(); - + if (isTransferring() || !canStartTransfer()) { return; /* transferring, don't try other connections yet */ } - + /* Try first the messages that can be delivered to final recipient */ if (exchangeDeliverableMessages() != null) { - return; - } - this.tryAllMessagesToAllConnections(); - } - + return; + } + this.tryAllMessagesToAllConnections(); + } + @Override public Message messageTransferred(String id, DTNHost from) { Message m = super.messageTransferred(id, from); @@ -137,33 +137,33 @@ public Message messageTransferred(String id, DTNHost from) { this.custodyMessages.put(id, SimClock.getTime()); return m; } - + @Override - protected void transferDone(Connection con) { + protected void transferDone(Connection con) { /* remove from custody messages (if it was there) */ - this.custodyMessages.remove(con.getMessage().getId()); + this.custodyMessages.remove(con.getMessage().getId()); } - + @Override public RoutingInfo getRoutingInfo() { RoutingInfo ri = super.getRoutingInfo(); - RoutingInfo immunity = new RoutingInfo("Immune to " + + RoutingInfo immunity = new RoutingInfo("Immune to " + this.recentMessages.size() + " messages"); - + for (String id : recentMessages.keySet()) { - RoutingInfo m = new RoutingInfo(id + " until " + - String.format("%.2f", + RoutingInfo m = new RoutingInfo(id + " until " + + String.format("%.2f", recentMessages.get(id) + this.immunityTime)); immunity.addMoreInfo(m); - } + } ri.addMoreInfo(immunity); - + return ri; - } - - @Override - public WaveRouter replicate() { - return new WaveRouter(this); - } - -} \ No newline at end of file + } + + @Override + public WaveRouter replicate() { + return new WaveRouter(this); + } + +} diff --git a/routing/maxprop/MaxPropDijkstra.java b/routing/maxprop/MaxPropDijkstra.java index d4c37c815..e1ef26787 100644 --- a/routing/maxprop/MaxPropDijkstra.java +++ b/routing/maxprop/MaxPropDijkstra.java @@ -1,6 +1,6 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ package routing.maxprop; @@ -33,7 +33,7 @@ public class MaxPropDijkstra { private Map prevNodes; /** Mapping of to other nodes' (whom this node has met) probability sets */ private Map probs; - + /** * Constructor. * @param probs A reference to the mapping of the known hosts meeting @@ -48,21 +48,21 @@ public MaxPropDijkstra(Map probs) { * @param firstHop The first hop router node */ private void initWith(Integer firstHop) { - this.unvisited = new PriorityQueue(PQ_INIT_SIZE, + this.unvisited = new PriorityQueue(PQ_INIT_SIZE, new DistanceComparator()); this.visited = new HashSet(); this.prevNodes = new HashMap(); this.distancesFromStart = new DistanceMap(); - + // set distance to source 0 and initialize unvisited queue this.distancesFromStart.put(firstHop, 0); this.unvisited.add(firstHop); } - + /** - * Calculates total costs to the given set of target nodes. The cost to + * Calculates total costs to the given set of target nodes. The cost to * a node is the sum of complements of probabilities that all the links - * come up as the next contact of the nodes. + * come up as the next contact of the nodes. * @param from The index (address) of the start node * @param to The address set of destination nodes * @return A map of (destination node, cost) tuples @@ -70,10 +70,10 @@ private void initWith(Integer firstHop) { public Map getCosts(Integer from, Set to) { Map distMap = new HashMap(); int nrofNodesToFind = to.size(); - + initWith(from); Integer node = null; - + // always take the node with shortest distance while ((node = unvisited.poll()) != null) { if (to.contains(node)) { @@ -83,15 +83,15 @@ public Map getCosts(Integer from, Set to) { if (nrofNodesToFind == 0) { break; // all requested nodes found } - } - + } + visited.add(node); // mark the node as visited relax(node); // add/update neighbor nodes' distances } - + return distMap; } - + /** * Relaxes the neighbors of a node (updates the shortest distances). * @param node The node whose neighbors are relaxed @@ -99,29 +99,29 @@ public Map getCosts(Integer from, Set to) { private void relax(Integer node) { double nodeDist = distancesFromStart.get(node); Collection neighbors; - + if (!this.probs.containsKey(node)) { return; // node's neighbors are not known } - + neighbors = this.probs.get(node).getAllProbs().keySet(); - + for (Integer n : neighbors) { if (visited.contains(n)) { continue; // skip visited nodes } - + // n node's distance from path's source node double nDist = nodeDist + getDistance(node, n); - - if (distancesFromStart.get(n) > nDist) { + + if (distancesFromStart.get(n) > nDist) { // stored distance > found dist -> update prevNodes.put(n, node); // for debugging setDistance(n, nDist); } } } - + /** * Sets the distance from source node to a node * @param n The node whose distance is set @@ -132,11 +132,11 @@ private void setDistance(Integer n, double distance) { distancesFromStart.put(n, distance); // update distance unvisited.add(n); // insert node to the new place in the queue } - + /** - * Returns the "distance" between two nodes, i.e., the complement of the + * Returns the "distance" between two nodes, i.e., the complement of the * probability that the next node "from" meets is "to". Works only if there - * exist a probability value for "from" meeting "to". + * exist a probability value for "from" meeting "to". * @param from The first node * @param to The second node * @return The distance between the two nodes @@ -146,14 +146,14 @@ private double getDistance(Integer from, Integer to) { " (it has met nodes " + probs.keySet() + ")"; return ( 1 - probs.get(from).getProbFor(to) ); } - + /** * Comparator that compares two nodes by their distance from * the source node. */ - private class DistanceComparator implements + private class DistanceComparator implements Comparator { - + /** * Compares two map nodes by their distance from the source node * @return -1, 0 or 1 if node1's distance is smaller, equal to, or @@ -162,7 +162,7 @@ private class DistanceComparator implements public int compare(Integer node1, Integer node2) { double dist1 = distancesFromStart.get(node1); double dist2 = distancesFromStart.get(node2); - + if (dist1 > dist2) { return 1; } @@ -174,20 +174,20 @@ else if (dist1 < dist2) { } } } - + /** - * Simple Map implementation for storing distances. + * Simple Map implementation for storing distances. */ private class DistanceMap { private HashMap map; - + /** * Constructor. Creates an empty distance map */ public DistanceMap() { - this.map = new HashMap(); + this.map = new HashMap(); } - + /** * Returns the distance to a node. If no distance value * is found, returns {@link MaxPropDijkstra#INFINITY} as the value. @@ -203,7 +203,7 @@ public double get(Integer node) { return INFINITY; } } - + /** * Puts a new distance value for a map node * @param node The node @@ -212,7 +212,7 @@ public double get(Integer node) { public void put(Integer node, double distance) { map.put(node, distance); } - + /** * Returns a string representation of the map's contents * @return a string representation of the map's contents @@ -221,4 +221,4 @@ public String toString() { return map.toString(); } } -} \ No newline at end of file +} diff --git a/routing/maxprop/MeetingProbabilitySet.java b/routing/maxprop/MeetingProbabilitySet.java index 022dd08f0..0a8fd64d6 100644 --- a/routing/maxprop/MeetingProbabilitySet.java +++ b/routing/maxprop/MeetingProbabilitySet.java @@ -1,173 +1,173 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package routing.maxprop; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import core.SimClock; - -/** - * Class for storing and manipulating the meeting probabilities for the MaxProp - * router module. - */ -public class MeetingProbabilitySet { - public static final int INFINITE_SET_SIZE = Integer.MAX_VALUE; - /** meeting probabilities (probability that the next node one meets is X) */ - private Map probs; - /** the time when this MPS was last updated */ - private double lastUpdateTime; - /** the alpha parameter */ - private double alpha; - private int maxSetSize; - - /** - * Constructor. Creates a probability set with empty node-probability - * mapping. - * @param maxSetSize Maximum size of the probability set; when the set is - * full, smallest values are dropped when new are added - */ - public MeetingProbabilitySet(int maxSetSize, double alpha) { - this.alpha = alpha; - this.probs = new HashMap(); - if (maxSetSize == INFINITE_SET_SIZE || maxSetSize < 1) { - this.probs = new HashMap(); - this.maxSetSize = INFINITE_SET_SIZE; - } else { - this.probs = new HashMap(maxSetSize); - this.maxSetSize = maxSetSize; - } - this.lastUpdateTime = 0; - } - - /** - * Constructor. Creates a probability set with empty node-probability - * mapping and infinite set size - */ - public MeetingProbabilitySet() { - this(INFINITE_SET_SIZE, 1); - } - - /** - * Constructor. Creates a probability set with equal probability for - * all the given node indexes. - */ - public MeetingProbabilitySet(double alpha, - List initiallyKnownNodes) { - this(INFINITE_SET_SIZE, alpha); - double prob = 1.0/initiallyKnownNodes.size(); - for (Integer i : initiallyKnownNodes) { - this.probs.put(i, prob); - } - } - - /** - * Updates meeting probability for the given node index. - *
 P(b) = P(b)_old + alpha
-	 * Normalize{P}
- * I.e., The probability of the given node index is increased by one and - * then all the probabilities are normalized so that their sum equals to 1. - * @param index The node index to update the probability for - */ - public void updateMeetingProbFor(Integer index) { - Map.Entry smallestEntry = null; - double smallestValue = Double.MAX_VALUE; - - this.lastUpdateTime = SimClock.getTime(); - - if (probs.size() == 0) { // first entry - probs.put(index, 1.0); - return; - } - - double newValue = getProbFor(index) + alpha; - probs.put(index, newValue); - - /* now the sum of all entries is 1+alpha; - * normalize to one by dividing all the entries by 1+alpha */ - for (Map.Entry entry : probs.entrySet()) { - entry.setValue(entry.getValue() / (1+alpha)); - if (entry.getValue() < smallestValue) { - smallestEntry = entry; - smallestValue = entry.getValue(); - } - - } - - if (probs.size() >= maxSetSize) { - core.Debug.p("Probsize: " + probs.size() + " dropping " + - probs.remove(smallestEntry.getKey())); - } - } - - public void updateMeetingProbFor(Integer index, double iet) { - probs.put(index, iet); - } - - /** - * Returns the current delivery probability value for the given node index - * @param index The index of the node to look the P for - * @return the current delivery probability value - */ - public double getProbFor(Integer index) { - if (probs.containsKey(index)) { - return probs.get(index); - } - else { - /* the node with the given index has not been met */ - return 0.0; - } - } - - /** - * Returns a reference to the probability map of this probability set - * @return a reference to the probability map of this probability set - */ - public Map getAllProbs() { - return this.probs; - } - - /** - * Returns the time when this probability set was last updated - * @return the time when this probability set was last updated - */ - public double getLastUpdateTime() { - return this.lastUpdateTime; - } - - /** - * Enables changing the alpha parameter dynamically - */ - public void setAlpha(double alpha) { - this.alpha = alpha; - } - - /** - * Returns a deep copy of the probability set - * @return a deep copy of the probability set - */ - public MeetingProbabilitySet replicate() { - MeetingProbabilitySet replica = new MeetingProbabilitySet( - this.maxSetSize, alpha); - - // do a deep copy - for (Map.Entry e : probs.entrySet()) { - replica.probs.put(e.getKey(), e.getValue().doubleValue()); - } - - replica.lastUpdateTime = this.lastUpdateTime; - return replica; - } - - /** - * Returns a String presentation of the probabilities - * @return a String presentation of the probabilities - */ - @Override - public String toString() { - return "probs: " + this.probs.toString(); - } -} \ No newline at end of file + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.maxprop; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import core.SimClock; + +/** + * Class for storing and manipulating the meeting probabilities for the MaxProp + * router module. + */ +public class MeetingProbabilitySet { + public static final int INFINITE_SET_SIZE = Integer.MAX_VALUE; + /** meeting probabilities (probability that the next node one meets is X) */ + private Map probs; + /** the time when this MPS was last updated */ + private double lastUpdateTime; + /** the alpha parameter */ + private double alpha; + private int maxSetSize; + + /** + * Constructor. Creates a probability set with empty node-probability + * mapping. + * @param maxSetSize Maximum size of the probability set; when the set is + * full, smallest values are dropped when new are added + */ + public MeetingProbabilitySet(int maxSetSize, double alpha) { + this.alpha = alpha; + this.probs = new HashMap(); + if (maxSetSize == INFINITE_SET_SIZE || maxSetSize < 1) { + this.probs = new HashMap(); + this.maxSetSize = INFINITE_SET_SIZE; + } else { + this.probs = new HashMap(maxSetSize); + this.maxSetSize = maxSetSize; + } + this.lastUpdateTime = 0; + } + + /** + * Constructor. Creates a probability set with empty node-probability + * mapping and infinite set size + */ + public MeetingProbabilitySet() { + this(INFINITE_SET_SIZE, 1); + } + + /** + * Constructor. Creates a probability set with equal probability for + * all the given node indexes. + */ + public MeetingProbabilitySet(double alpha, + List initiallyKnownNodes) { + this(INFINITE_SET_SIZE, alpha); + double prob = 1.0/initiallyKnownNodes.size(); + for (Integer i : initiallyKnownNodes) { + this.probs.put(i, prob); + } + } + + /** + * Updates meeting probability for the given node index. + *
 P(b) = P(b)_old + alpha
+	 * Normalize{P}
+ * I.e., The probability of the given node index is increased by one and + * then all the probabilities are normalized so that their sum equals to 1. + * @param index The node index to update the probability for + */ + public void updateMeetingProbFor(Integer index) { + Map.Entry smallestEntry = null; + double smallestValue = Double.MAX_VALUE; + + this.lastUpdateTime = SimClock.getTime(); + + if (probs.size() == 0) { // first entry + probs.put(index, 1.0); + return; + } + + double newValue = getProbFor(index) + alpha; + probs.put(index, newValue); + + /* now the sum of all entries is 1+alpha; + * normalize to one by dividing all the entries by 1+alpha */ + for (Map.Entry entry : probs.entrySet()) { + entry.setValue(entry.getValue() / (1+alpha)); + if (entry.getValue() < smallestValue) { + smallestEntry = entry; + smallestValue = entry.getValue(); + } + + } + + if (probs.size() >= maxSetSize) { + core.Debug.p("Probsize: " + probs.size() + " dropping " + + probs.remove(smallestEntry.getKey())); + } + } + + public void updateMeetingProbFor(Integer index, double iet) { + probs.put(index, iet); + } + + /** + * Returns the current delivery probability value for the given node index + * @param index The index of the node to look the P for + * @return the current delivery probability value + */ + public double getProbFor(Integer index) { + if (probs.containsKey(index)) { + return probs.get(index); + } + else { + /* the node with the given index has not been met */ + return 0.0; + } + } + + /** + * Returns a reference to the probability map of this probability set + * @return a reference to the probability map of this probability set + */ + public Map getAllProbs() { + return this.probs; + } + + /** + * Returns the time when this probability set was last updated + * @return the time when this probability set was last updated + */ + public double getLastUpdateTime() { + return this.lastUpdateTime; + } + + /** + * Enables changing the alpha parameter dynamically + */ + public void setAlpha(double alpha) { + this.alpha = alpha; + } + + /** + * Returns a deep copy of the probability set + * @return a deep copy of the probability set + */ + public MeetingProbabilitySet replicate() { + MeetingProbabilitySet replica = new MeetingProbabilitySet( + this.maxSetSize, alpha); + + // do a deep copy + for (Map.Entry e : probs.entrySet()) { + replica.probs.put(e.getKey(), e.getValue().doubleValue()); + } + + replica.lastUpdateTime = this.lastUpdateTime; + return replica; + } + + /** + * Returns a String presentation of the probabilities + * @return a String presentation of the probabilities + */ + @Override + public String toString() { + return "probs: " + this.probs.toString(); + } +} diff --git a/routing/maxprop/package.html b/routing/maxprop/package.html index 583c1fc11..3058ba8a3 100644 --- a/routing/maxprop/package.html +++ b/routing/maxprop/package.html @@ -1,8 +1,8 @@ - - - - -Contains MaxProp routing module specific classes. - - - \ No newline at end of file + + + + +Contains MaxProp routing module specific classes. + + + diff --git a/routing/package.html b/routing/package.html index 4830dc966..caec4e994 100644 --- a/routing/package.html +++ b/routing/package.html @@ -1,14 +1,14 @@ - - - - -Contains all the router classes who decide how to handle the messages. -All router classes must be in this package and must extend the -{@link routing.MessageRouter} (when creating new routers, extending -{@link routing.ActiveRouter} might make sense) class so they can be -dynamically loaded to the simulator. The classes to load can be specified -through {@link core.Settings} class' settings source. See MessageRouter class -and classes extending it for details about the settings. - - - \ No newline at end of file + + + + +Contains all the router classes who decide how to handle the messages. +All router classes must be in this package and must extend the +{@link routing.MessageRouter} (when creating new routers, extending +{@link routing.ActiveRouter} might make sense) class so they can be +dynamically loaded to the simulator. The classes to load can be specified +through {@link core.Settings} class' settings source. See MessageRouter class +and classes extending it for details about the settings. + + + diff --git a/routing/schedule/ScheduleDijkstra.java b/routing/schedule/ScheduleDijkstra.java index fc7244173..2f1bff8eb 100644 --- a/routing/schedule/ScheduleDijkstra.java +++ b/routing/schedule/ScheduleDijkstra.java @@ -1,211 +1,211 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ - -package routing.schedule; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.PriorityQueue; -import java.util.Queue; -import java.util.Set; - -/** - * Dijkstra's shortest path implementation for schedule data - */ -/* TODO: combine this with movement.map.DijkstraPathFinder? */ -public class ScheduleDijkstra { - /** Value for infinite distance */ - private static final Double INFINITY = Double.MAX_VALUE; - /** Initial size of the priority queue */ - private static final int PQ_INIT_SIZE = 11; - - /** Map of the times when one could be at certain node */ - private TimeMap times; - /** Set of already visited nodes (where the shortest path is known) */ - private Set visited; - /** Priority queue of unvisited nodes discovered so far */ - private Queue unvisited; - /** Map of previous schedule on the shortest path(s) */ - private Map prevHops; - /** Oracle that know all schedules */ - private ScheduleOracle oracle; - - /** - * Constructor. - * @param oracle The schedule oracle - * all nodes are OK - */ - public ScheduleDijkstra(ScheduleOracle oracle) { - this.oracle = oracle; - } - - /** - * Initializes a new search with a source node - * @param node The path's source node - * @param time The time when the path starts - */ - private void initWith(Integer node, double time) { - this.unvisited = new PriorityQueue(PQ_INIT_SIZE, - new DurationComparator()); - this.visited = new HashSet(); - this.prevHops = new HashMap(); - this.times = new TimeMap(); - - this.times.put(node, time); - this.unvisited.add(node); - } - - /** - * Finds and returns the fastest path between two destinations - * @param from The source of the path - * @param to The destination of the path - * @param time The time when the path starts - * @return a shortest path between the source and destination nodes in - * a list of Integers or an empty list if such path is not available - */ - public List getShortestPath(Integer from, Integer to, - double time){ - List path = new ArrayList(); - assert time >= 0.0 : "Can't use negative start time"; - - if (from.compareTo(to) == 0) { - return path; - } - - initWith(from, time); - Integer node = null; - - while ((node = unvisited.poll()) != null) { - if (node.equals(to)) { - break; - } - - visited.add(node); - relax(node); - } - - if (node != null) { // found a path - ScheduleEntry prev = prevHops.get(to); - while (prev.getFrom() != from) { - path.add(0, prev); - prev = prevHops.get(prev.getFrom()); - } - - path.add(0, prev); - } - - return path; - } - - /** - * Relaxes the neighbors of a node (updates the shortest distances). - * @param node The node whose neighbors are relaxed - */ - private void relax(Integer node) { - double timeNow = times.get(node); - int to; - double timeTo; - - for (ScheduleEntry se : oracle.getConnected(node, timeNow)) { - to = se.getTo(); - if (visited.contains(to)) { - continue; // skip visited nodes - } - - timeTo = se.getTime() + se.getDuration(); - - if (timeTo < times.get(to)) { - prevHops.put(to, se); - setTime(to, timeTo); - } - } - } - - /** - * Sets the time when at a node - * @param n The node whose time is set - * @param time The time when at given node - */ - private void setTime(Integer n, double time) { - unvisited.remove(n); - times.put(n, time); - unvisited.add(n); - } - - /** - * Comparator that compares two nodes by their journey duration - */ - private class DurationComparator implements Comparator { - - /** - * Compares two nodes by their time to get there - * @return -1, 0 or 1 if node1's time is smaller, equal to, or - * bigger than node2's - */ - public int compare(Integer node1, Integer node2) { - double time1 = times.get(node1); - double time2 = times.get(node2); - - if (time1 > time2) { - return 1; - } - else if (time1 < time2) { - return -1; - } - else { - return 0; - } - } - } - - private class TimeMap { - private HashMap map; - - /** - * Constructor. Creates an empty map - */ - public TimeMap() { - this.map = new HashMap(); - } - - /** - * Returns the currently known smallest time one has a path for to the - * given node. If no time value is found, returns - * {@link ScheduleDijkstra#INFINITY} as the value. - * @param node The node whose time is requested - * @return The time when one could be at that node - */ - public double get(Integer node) { - Double value = map.get(node); - if (value != null) { - return value; - } - else { - return INFINITY; - } - } - - /** - * Puts a new time value for a node - * @param node The node - * @param time Time at that node - */ - public void put(Integer node, double time) { - map.put(node, time); - } - - /** - * Returns a string representation of the map's contents - * @return a string representation of the map's contents - */ - public String toString() { - return map.toString(); - } - } -} \ No newline at end of file + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing.schedule; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.Set; + +/** + * Dijkstra's shortest path implementation for schedule data + */ +/* TODO: combine this with movement.map.DijkstraPathFinder? */ +public class ScheduleDijkstra { + /** Value for infinite distance */ + private static final Double INFINITY = Double.MAX_VALUE; + /** Initial size of the priority queue */ + private static final int PQ_INIT_SIZE = 11; + + /** Map of the times when one could be at certain node */ + private TimeMap times; + /** Set of already visited nodes (where the shortest path is known) */ + private Set visited; + /** Priority queue of unvisited nodes discovered so far */ + private Queue unvisited; + /** Map of previous schedule on the shortest path(s) */ + private Map prevHops; + /** Oracle that know all schedules */ + private ScheduleOracle oracle; + + /** + * Constructor. + * @param oracle The schedule oracle + * all nodes are OK + */ + public ScheduleDijkstra(ScheduleOracle oracle) { + this.oracle = oracle; + } + + /** + * Initializes a new search with a source node + * @param node The path's source node + * @param time The time when the path starts + */ + private void initWith(Integer node, double time) { + this.unvisited = new PriorityQueue(PQ_INIT_SIZE, + new DurationComparator()); + this.visited = new HashSet(); + this.prevHops = new HashMap(); + this.times = new TimeMap(); + + this.times.put(node, time); + this.unvisited.add(node); + } + + /** + * Finds and returns the fastest path between two destinations + * @param from The source of the path + * @param to The destination of the path + * @param time The time when the path starts + * @return a shortest path between the source and destination nodes in + * a list of Integers or an empty list if such path is not available + */ + public List getShortestPath(Integer from, Integer to, + double time){ + List path = new ArrayList(); + assert time >= 0.0 : "Can't use negative start time"; + + if (from.compareTo(to) == 0) { + return path; + } + + initWith(from, time); + Integer node = null; + + while ((node = unvisited.poll()) != null) { + if (node.equals(to)) { + break; + } + + visited.add(node); + relax(node); + } + + if (node != null) { // found a path + ScheduleEntry prev = prevHops.get(to); + while (prev.getFrom() != from) { + path.add(0, prev); + prev = prevHops.get(prev.getFrom()); + } + + path.add(0, prev); + } + + return path; + } + + /** + * Relaxes the neighbors of a node (updates the shortest distances). + * @param node The node whose neighbors are relaxed + */ + private void relax(Integer node) { + double timeNow = times.get(node); + int to; + double timeTo; + + for (ScheduleEntry se : oracle.getConnected(node, timeNow)) { + to = se.getTo(); + if (visited.contains(to)) { + continue; // skip visited nodes + } + + timeTo = se.getTime() + se.getDuration(); + + if (timeTo < times.get(to)) { + prevHops.put(to, se); + setTime(to, timeTo); + } + } + } + + /** + * Sets the time when at a node + * @param n The node whose time is set + * @param time The time when at given node + */ + private void setTime(Integer n, double time) { + unvisited.remove(n); + times.put(n, time); + unvisited.add(n); + } + + /** + * Comparator that compares two nodes by their journey duration + */ + private class DurationComparator implements Comparator { + + /** + * Compares two nodes by their time to get there + * @return -1, 0 or 1 if node1's time is smaller, equal to, or + * bigger than node2's + */ + public int compare(Integer node1, Integer node2) { + double time1 = times.get(node1); + double time2 = times.get(node2); + + if (time1 > time2) { + return 1; + } + else if (time1 < time2) { + return -1; + } + else { + return 0; + } + } + } + + private class TimeMap { + private HashMap map; + + /** + * Constructor. Creates an empty map + */ + public TimeMap() { + this.map = new HashMap(); + } + + /** + * Returns the currently known smallest time one has a path for to the + * given node. If no time value is found, returns + * {@link ScheduleDijkstra#INFINITY} as the value. + * @param node The node whose time is requested + * @return The time when one could be at that node + */ + public double get(Integer node) { + Double value = map.get(node); + if (value != null) { + return value; + } + else { + return INFINITY; + } + } + + /** + * Puts a new time value for a node + * @param node The node + * @param time Time at that node + */ + public void put(Integer node, double time) { + map.put(node, time); + } + + /** + * Returns a string representation of the map's contents + * @return a string representation of the map's contents + */ + public String toString() { + return map.toString(); + } + } +} diff --git a/routing/schedule/ScheduleEntry.java b/routing/schedule/ScheduleEntry.java index b1c0183cc..7f6150b1c 100644 --- a/routing/schedule/ScheduleEntry.java +++ b/routing/schedule/ScheduleEntry.java @@ -1,111 +1,111 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package routing.schedule; - -import java.io.Serializable; - -public class ScheduleEntry implements Serializable { - private static final long serialVersionUID = 42L; - - private double time; - private int from; - private int to; - private int via; - private double delta; - private double duration; - private int usageCount; - - /** - * Constructor of new schedule entry - * @param time When the journey from "from" starts - * @param from The source - * @param via The node that takes us there (or -1 if n/a) - * @param to The destination - * @param duration Time it takes from the source to destination - */ - public ScheduleEntry(double time, int from, int via, int to, - double duration) { - this.time = time; - this.from = from; - this.via = via; - this.to = to; - this.duration = duration; - this.delta = 0; - this.usageCount = 0; - } - - /** - * Returns time + delta - * @return the time - */ - public double getTime() { - return time + delta; - } - - /** - * @return the destination - */ - public int getTo() { - return to; - } - - /** - * @return the source - */ - public int getFrom() { - return from; - } - - /** - * @return the via - */ - public int getVia() { - return via; - } - - /** - * Return the time it takes to get from source to destination - * @return the duration - */ - public double getDuration() { - return duration; - } - - public double getDestinationTime() { - return this.getTime() + this.getDuration(); - } - - /** - * @return the delta - */ - public double getDelta() { - return delta; - } - - /** - * @param delta the delta to set - */ - public void setDelta(double delta) { - this.delta = delta; - } - - /** - * @return the usageCount - */ - public int getUsageCount() { - return usageCount; - } - - public void increaseUsageCount() { - this.usageCount++; - } - - @Override - public String toString() { - return time + "(+" + delta + "): " + from + "->" - + (via > 0 ? via + "->" : "") + to + " (" + duration + ")"; - } - -} \ No newline at end of file + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.schedule; + +import java.io.Serializable; + +public class ScheduleEntry implements Serializable { + private static final long serialVersionUID = 42L; + + private double time; + private int from; + private int to; + private int via; + private double delta; + private double duration; + private int usageCount; + + /** + * Constructor of new schedule entry + * @param time When the journey from "from" starts + * @param from The source + * @param via The node that takes us there (or -1 if n/a) + * @param to The destination + * @param duration Time it takes from the source to destination + */ + public ScheduleEntry(double time, int from, int via, int to, + double duration) { + this.time = time; + this.from = from; + this.via = via; + this.to = to; + this.duration = duration; + this.delta = 0; + this.usageCount = 0; + } + + /** + * Returns time + delta + * @return the time + */ + public double getTime() { + return time + delta; + } + + /** + * @return the destination + */ + public int getTo() { + return to; + } + + /** + * @return the source + */ + public int getFrom() { + return from; + } + + /** + * @return the via + */ + public int getVia() { + return via; + } + + /** + * Return the time it takes to get from source to destination + * @return the duration + */ + public double getDuration() { + return duration; + } + + public double getDestinationTime() { + return this.getTime() + this.getDuration(); + } + + /** + * @return the delta + */ + public double getDelta() { + return delta; + } + + /** + * @param delta the delta to set + */ + public void setDelta(double delta) { + this.delta = delta; + } + + /** + * @return the usageCount + */ + public int getUsageCount() { + return usageCount; + } + + public void increaseUsageCount() { + this.usageCount++; + } + + @Override + public String toString() { + return time + "(+" + delta + "): " + from + "->" + + (via > 0 ? via + "->" : "") + to + " (" + duration + ")"; + } + +} diff --git a/routing/schedule/ScheduleOracle.java b/routing/schedule/ScheduleOracle.java index f7125c691..61236fbb6 100644 --- a/routing/schedule/ScheduleOracle.java +++ b/routing/schedule/ScheduleOracle.java @@ -1,91 +1,91 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package routing.schedule; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ScheduleOracle implements Serializable{ - private static final long serialVersionUID = 42L; - - Map> schedules; - - public ScheduleOracle() { - this.schedules = new HashMap>(); - } - - /** - * Adds a new schedule entry to the oracle - * @param start Start time - * @param from Source of the connection - * @param via The node that goes from "from" to "via" (or -1 for n/a) - * @param to Destination of the connection - * @param duration How long it takes to get to destination - */ - public void addEntry(double start, int from, int via, int to, - double duration) { - List list = schedules.get(from); - - if (list == null) { /* first entry for the from */ - list = new ArrayList(); - schedules.put(from, list); - } - - list.add(new ScheduleEntry(start, from, via, to, duration)); - } - - /** - * Adds a new schedule entry to the oracle - * @param start Start time - * @param from Source of the connection - * @param to Destination of the connection - * @param duration How long it takes to get to destination - */ - public void addEntry(double start, int from, int to,double duration) { - addEntry(start, from, -1, to, duration); - } - - /** - * Returns a list of schedule entries for nodes reachable after given time - * from the given node - * @param from The source node - * @param time Time to start - * @return List of reachable nodes - */ - public List getConnected(int from, double time) { - List connected = new ArrayList(); - List all = schedules.get(from); - - if (all == null) { - return connected; - } - - for (ScheduleEntry s : all) { - if (s.getTime() >= time) { - connected.add(s); - } - } - - return connected; - } - - /** - * Returns all schedule entries - * @return all schedule entries - */ - public List getEntries() { - List entries = new ArrayList(); - for (List list : schedules.values()) { - for (ScheduleEntry se : list) { - entries.add(se); - } - } - - return entries; - } -} \ No newline at end of file + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.schedule; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ScheduleOracle implements Serializable{ + private static final long serialVersionUID = 42L; + + Map> schedules; + + public ScheduleOracle() { + this.schedules = new HashMap>(); + } + + /** + * Adds a new schedule entry to the oracle + * @param start Start time + * @param from Source of the connection + * @param via The node that goes from "from" to "via" (or -1 for n/a) + * @param to Destination of the connection + * @param duration How long it takes to get to destination + */ + public void addEntry(double start, int from, int via, int to, + double duration) { + List list = schedules.get(from); + + if (list == null) { /* first entry for the from */ + list = new ArrayList(); + schedules.put(from, list); + } + + list.add(new ScheduleEntry(start, from, via, to, duration)); + } + + /** + * Adds a new schedule entry to the oracle + * @param start Start time + * @param from Source of the connection + * @param to Destination of the connection + * @param duration How long it takes to get to destination + */ + public void addEntry(double start, int from, int to,double duration) { + addEntry(start, from, -1, to, duration); + } + + /** + * Returns a list of schedule entries for nodes reachable after given time + * from the given node + * @param from The source node + * @param time Time to start + * @return List of reachable nodes + */ + public List getConnected(int from, double time) { + List connected = new ArrayList(); + List all = schedules.get(from); + + if (all == null) { + return connected; + } + + for (ScheduleEntry s : all) { + if (s.getTime() >= time) { + connected.add(s); + } + } + + return connected; + } + + /** + * Returns all schedule entries + * @return all schedule entries + */ + public List getEntries() { + List entries = new ArrayList(); + for (List list : schedules.values()) { + for (ScheduleEntry se : list) { + entries.add(se); + } + } + + return entries; + } +} diff --git a/routing/util/EnergyModel.java b/routing/util/EnergyModel.java index bb9213e3c..600b15e47 100644 --- a/routing/util/EnergyModel.java +++ b/routing/util/EnergyModel.java @@ -1,50 +1,50 @@ -/* +/* * Copyright 2011 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing.util; +package routing.util; import java.util.Random; -import core.*; - -/** +import core.*; + +/** * Energy model for routing modules. Handles power use from scanning (device - * discovery), scan responses, and data transmission. If scanning is done more + * discovery), scan responses, and data transmission. If scanning is done more * often than 1/s, constant scanning is assumed (and power consumption does not - * increase from {@link #scanEnergy} value). - */ + * increase from {@link #scanEnergy} value). + */ public class EnergyModel implements ModuleCommunicationListener { - /** Initial units of energy -setting id ({@value}). Can be either a + /** Initial units of energy -setting id ({@value}). Can be either a * single value, or a range of two values. In the latter case, the used * value is a uniformly distributed random value between the two values. */ public static final String INIT_ENERGY_S = "initialEnergy"; - + /** Energy usage per scanning (device discovery) -setting id ({@value}). */ public static final String SCAN_ENERGY_S = "scanEnergy"; - - /** Energy usage per scanning (device discovery) response -setting id + + /** Energy usage per scanning (device discovery) response -setting id * ({@value}). */ public static final String SCAN_RSP_ENERGY_S = "scanResponseEnergy"; - + /** Energy usage per second when sending -setting id ({@value}). */ public static final String TRANSMIT_ENERGY_S = "transmitEnergy"; - + /** Base energy usage per second -setting id ({@value}). */ public static final String BASE_ENERGY_S = "baseEnergy"; - - /** Energy update warmup period -setting id ({@value}). Defines the - * simulation time after which the energy level starts to decrease due to - * scanning, transmissions, etc. Default value = 0. If value of "-1" is - * defined, uses the value from the report warmup setting - * {@link report.Report#WARMUP_S} from the namespace + + /** Energy update warmup period -setting id ({@value}). Defines the + * simulation time after which the energy level starts to decrease due to + * scanning, transmissions, etc. Default value = 0. If value of "-1" is + * defined, uses the value from the report warmup setting + * {@link report.Report#WARMUP_S} from the namespace * {@value report.Report#REPORT_NS}. */ public static final String WARMUP_S = "energyWarmup"; - /** {@link ModuleCommunicationBus} identifier for the "current amount of + /** {@link ModuleCommunicationBus} identifier for the "current amount of * energy left" variable. Value type: double */ public static final String ENERGY_VALUE_ID = "Energy.value"; - + /** Initial energy levels from the settings */ private final double[] initEnergy; private double warmupTime; @@ -60,24 +60,24 @@ public class EnergyModel implements ModuleCommunicationListener { private double lastUpdate; private ModuleCommunicationBus comBus; private static Random rng = null; - - /** - * Constructor. Creates a new message router based on the settings in - * the given Settings object. - * @param s The settings object - */ - public EnergyModel(Settings s) { + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public EnergyModel(Settings s) { this.initEnergy = s.getCsvDoubles(INIT_ENERGY_S); - + if (this.initEnergy.length != 1 && this.initEnergy.length != 2) { - throw new SettingsError(INIT_ENERGY_S + " setting must have " + + throw new SettingsError(INIT_ENERGY_S + " setting must have " + "either a single value or two comma separated values"); } - + this.scanEnergy = s.getDouble(SCAN_ENERGY_S); this.transmitEnergy = s.getDouble(TRANSMIT_ENERGY_S); this.scanResponseEnergy = s.getDouble(SCAN_RSP_ENERGY_S); - + if (s.contains(WARMUP_S)) { this.warmupTime = s.getInt(WARMUP_S); if (this.warmupTime == -1) { @@ -89,7 +89,7 @@ public EnergyModel(Settings s) { this.warmupTime = 0; } } - + /** * Copy constructor. * @param proto The model prototype where setting values are copied from @@ -104,13 +104,13 @@ protected EnergyModel(EnergyModel proto) { this.comBus = null; this.lastUpdate = 0; } - + public EnergyModel replicate() { return new EnergyModel(this); } - + /** - * Sets the current energy level into the given range using uniform + * Sets the current energy level into the given range using uniform * random distribution. * @param range The min and max values of the range, or if only one value * is given, that is used as the energy level @@ -123,19 +123,19 @@ protected void setEnergy(double range[]) { if (rng == null) { rng = new Random((int)(range[0] + range[1])); } - this.currentEnergy = range[0] + + this.currentEnergy = range[0] + rng.nextDouble() * (range[1] - range[0]); } } - + /** * Returns the current energy level * @return the current energy level */ public double getEnergy() { return this.currentEnergy; - } - + } + /** * Updates the current energy so that the given amount is reduced from it. * If the energy level goes below zero, sets the level to zero. @@ -146,19 +146,19 @@ protected void reduceEnergy(double amount) { if (SimClock.getTime() < this.warmupTime) { return; } - + if (comBus == null) { return; /* model not initialized (via update) yet */ } - + if (amount >= this.currentEnergy) { comBus.updateProperty(ENERGY_VALUE_ID, 0.0); } else { comBus.updateDouble(ENERGY_VALUE_ID, -amount); } - + } - + /** * Reduces the energy reserve for the amount that is used when another * host connects (does device discovery) @@ -166,27 +166,27 @@ protected void reduceEnergy(double amount) { public void reduceDiscoveryEnergy() { reduceEnergy(this.scanResponseEnergy); } - + /** * Reduces the energy reserve for the amount that is used by sending data - * and scanning for the other nodes. + * and scanning for the other nodes. */ public void update(NetworkInterface iface, ModuleCommunicationBus comBus) { double simTime = SimClock.getTime(); double delta = simTime - this.lastUpdate; - + if (this.comBus == null) { this.comBus = comBus; this.comBus.addProperty(ENERGY_VALUE_ID, this.currentEnergy); this.comBus.subscribe(ENERGY_VALUE_ID, this); } - + if (simTime > this.lastUpdate && iface.isTransferring()) { /* sending or receiving data */ reduceEnergy(delta * this.transmitEnergy); } this.lastUpdate = simTime; - + if (iface.isScanning()) { /* scanning at this update round */ if (iface.getTransmitRange() > 0) { @@ -198,7 +198,7 @@ public void update(NetworkInterface iface, ModuleCommunicationBus comBus) { } } } - + /** * Called by the combus if the energy value is changed * @param key The energy ID @@ -207,5 +207,5 @@ public void update(NetworkInterface iface, ModuleCommunicationBus comBus) { public void moduleValueChanged(String key, Object newValue) { this.currentEnergy = (Double)newValue; } - -} \ No newline at end of file + +} diff --git a/routing/util/MessageTransferAcceptPolicy.java b/routing/util/MessageTransferAcceptPolicy.java index 5541150f4..de577d272 100644 --- a/routing/util/MessageTransferAcceptPolicy.java +++ b/routing/util/MessageTransferAcceptPolicy.java @@ -1,325 +1,325 @@ -/* - * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package routing.util; - -import java.util.ArrayList; - -import util.Range; -import util.Tuple; - -import core.ArithmeticCondition; -import core.Connection; -import core.DTNHost; -import core.Message; -import core.ModuleCommunicationBus; -import core.Settings; - -/** - *

Message transfer accepting policy module. Can be used to decide whether - * certain messages should be accepted or not. Shared by a whole node group, but - * uses the module communication bus of each node in question.

- *

Supports 3 different modes: "simple policy", Hop Count, and - * ModuleCommunicationBus (MCB) values. With simple policy, hosts that are - * accepted as the source of a message (i.e., the original message sender) when - * receiving a message are listed (comma separated values) using the - * {@link #FROM_RPOLICY_S} setting - * (when sending, using {@link #FROM_SPOLICY_S}) and hosts that are accepted as - * the destination when receiving are listed using {@link #TO_RPOLICY_S} - * (and when sending, using {@link #TO_SPOLICY_S}). By default, any message is - * accepted.

- * With ModuleCommunicationBus values, the amount of conditions is first defined - * with {@link #NROF_MCBCS_S} and sending/receiving conditions are defined - * as {@link ArithmeticCondition} with {@link #MCBACS_S} or {@link #MCBACR_S} - * and the ModuleCommuncationBus IDs where to get values from to use with the - * condition with {@link #MCBCVS_S} and {@link #MCBCVR_S}.

- *

The MCB conditions are checked first, and if none of them match, - * simple policy conditions are checked. If they don't exists, - * or one of them matches, hop count policy is checked. If that doesn't exist - * or matches to message's hop count, transfer is accepted. Otherwise transfer - * is denied. - *

- * @author Ari - */ -public class MessageTransferAcceptPolicy { - - /** Namespace for all "Message Transfer Accept policy" settings ({@value})*/ - public static final String MTA_POLICY_NS = "mtaPolicy"; - - /** Number of Module Communication Bus Conditions -setting id ({@value}). - * Two comma separated values. Defines the number of receiving and number of - * sending conditions to read from the settings. */ - public static final String NROF_MCBCS_S = "nrofMCBACs"; - - /** Module Communication Bus Arithmetic Condition for Receiving -setting id - * ({@value}). {@link ArithmeticCondition}. Defines one arithmetic condition - * to use for receiving messages. */ - public static final String MCBACR_S = "MCBRcondition"; - /** Module Communication Bus Arithmetic Condition for Sending -setting id - * ({@value}). {@link ArithmeticCondition}. */ - public static final String MCBACS_S = "MCBScondition"; - - /** Module Communication Bus Condition Value for Receiving -setting id - * ({@value}). String. Defines the ID to use with the receiving - * condition. */ - public static final String MCBCVR_S = "MCBRvalue"; - /** Module Communication Bus Condition Value for Sending -setting id - * ({@value}). String. Defines the ID to use with the sending - * condition. */ - public static final String MCBCVS_S = "MCBSvalue"; - - /** The valued used in to-policy to refer to this host ({@value}) */ - public static final int TO_ME_VALUE = -1; - - /** Simple-policy accept-to -setting id ({@value}). Integer list. - * Defines the addresses of the hosts accepted as the destination of a - * message when receiving messages. Special value {@link #TO_ME_VALUE} - * refers to this host. */ - public static final String TO_RPOLICY_S = "toReceivePolicy"; - - /** Simple-policy accept-from -setting id ({@value}). Integer list. - * Defines the addresses of the hosts accepted as the source of a - * message when receiving messages. Special value {@link #TO_ME_VALUE} - * refers to this host. */ - public static final String FROM_RPOLICY_S = "fromReceivePolicy"; - - /** Simple-policy accept-to -setting id ({@value}). Integer list. - * Defines the addresses of the hosts accepted as the destination of a - * message when sending messages. Special value {@link #TO_ME_VALUE} refers - * to this host (but doesn't usually make much sense here). */ - public static final String TO_SPOLICY_S = "toSendPolicy"; - - /**

Simple-policy accept-from -setting id ({@value}). Integer list. - * Defines the addresses of the hosts accepted as the source of a - * message when sending messages. Special value {@link #TO_ME_VALUE} refers - * to this host.

- *

Note: if this setting is defined and the {@link #TO_ME_VALUE} - * is NOT listed, the hosts own messages are not sent anywhere.

*/ - public static final String FROM_SPOLICY_S = "fromSendPolicy"; - - /** Hop count forwarding receive policy -setting id ({@value}). - * {@link ArithmeticCondition}. Defines condition for the message hop - * count; if the condition does not match, the message is rejected, - * unless it is destined to this node. */ - public static final String HOPCOUNT_RPOLICY_S = "hopCountReceivePolicy"; - /** Hop count forwarding send policy -setting id ({@value}). - * {@link ArithmeticCondition}. Defines condition for the message hop - * count; if the condition does not match, the message is not offered - * to other nodes, unless it would be delivered to the final destination. */ - public static final String HOPCOUNT_SPOLICY_S = "hopCountSendPolicy"; - - private ArrayList> recvConditions = null; - private ArrayList> sendConditions = null; - - private Range[] toSendPolicy = null; - private Range[] fromSendPolicy = null; - private Range[] toReceivePolicy = null; - private Range[] fromReceivePolicy = null; - private ArithmeticCondition hopCountSendPolicy = null; - private ArithmeticCondition hopCountReceivePolicy = null; - - public MessageTransferAcceptPolicy(Settings nsSettings) { - Settings s; - - if (! nsSettings.contains(MTA_POLICY_NS)) { - return; /* no (or "default") policy */ - } - - s = new Settings(nsSettings.getSetting(MTA_POLICY_NS)); - addMCBCs(s); - - if (s.contains(TO_SPOLICY_S)) { - this.toSendPolicy = s.getCsvRanges(TO_SPOLICY_S); - } - if (s.contains(FROM_SPOLICY_S)) { - this.fromSendPolicy = s.getCsvRanges(FROM_SPOLICY_S); - } - if (s.contains(TO_RPOLICY_S)) { - this.toReceivePolicy = s.getCsvRanges(TO_RPOLICY_S); - } - if (s.contains(FROM_RPOLICY_S)) { - this.fromReceivePolicy = s.getCsvRanges(FROM_RPOLICY_S); - } - if (s.contains(HOPCOUNT_SPOLICY_S)) { - hopCountSendPolicy = s.getCondition(HOPCOUNT_SPOLICY_S); - } - if (s.contains(HOPCOUNT_RPOLICY_S)) { - hopCountReceivePolicy = s.getCondition(HOPCOUNT_RPOLICY_S); - } - } - - /** - * Adds MessageCommunicationBus Conditions - * @param s Settings where the conditions are read from - */ - private void addMCBCs(Settings s) { - if (!s.contains(NROF_MCBCS_S)) { - return; /* no transfer policy defined */ - } - - int[] nrof = s.getCsvInts(NROF_MCBCS_S); - if (nrof[0] > 0) { /* create lists only if needed */ - this.recvConditions = - new ArrayList>(); - } - if (nrof[1] > 0) { - this.sendConditions = - new ArrayList>(); - } - - addConditions(s, MCBACR_S, MCBCVR_S, this.recvConditions, nrof[0]); - addConditions(s, MCBACS_S, MCBCVS_S, this.sendConditions, nrof[1]); - } - - /** - * Read conditions from the settings and add them to the given list - * @param s The settings object - * @param cPrefix Condition setting prefix - * @param vPrefix Value setting prefix - * @param list The list to add conditions - * @param nrof The number of settings to read - */ - private void addConditions(Settings s, String cPrefix, String vPrefix, - ArrayList> list, - int nrof) { - for (int i=1; i<=nrof; i++) { - ArithmeticCondition ac = s.getCondition(cPrefix + i); - String mcbValue = s.getSetting(vPrefix + i); - list.add(new Tuple(mcbValue, ac)); - } - } - - /** - * Checks all the Module Communication Bus conditions and returns false - * if at least one of them failed. - * @param mcb The module communication bus to use - * @param receiving Should check using the receiving conditions list; - * if false, the sending conditions list is used - * @return true if all conditions evaluated to true - */ - private boolean checkMcbConditions(ModuleCommunicationBus mcb, - boolean receiving) { - ArrayList> list = - (receiving ? this.recvConditions : this.sendConditions); - - if (list == null) { - return true; - } - - for (Tuple t : list) { - if (!mcb.containsProperty(t.getKey())) { - continue; /* no value in the bus; can't fail condition */ - } - if (t.getValue().isTrueFor(mcb.getDouble(t.getKey(), 0))){ - return false; - } - } - - return true; - } - - /** - * Checks if the host's address is contained in the policy list - * (or {@value #TO_ME_VALUE} is contained and the address matches to - * thisHost parameter) - * @param host The hosts whose address to check - * @param policy The list of accepted addresses - * @param thisHost The address of this host - * @return True if the address was in the policy list, or the policy list - * was null - */ - private boolean checkSimplePolicy(DTNHost host, Range [] policy, - int thisHost) { - int address; - - if (policy == null) { - return true; - } - - address = host.getAddress(); - - for (Range r : policy) { - if (r.isInRange(TO_ME_VALUE) && address == thisHost) { - return true; - } - else if (r.isInRange(address)) { - return true; - } - } - return false; - } - - /** - * Checks the given messages hop count against the given policy arithmetic - * condition - * @param m The message whose hop count is checked - * @param ac The policy arithmetic condition - * @return True if the condition is null or the hop count matches to the - * condition, false otherwise - */ - private boolean checkHopCountPolicy(Message m, ArithmeticCondition ac) { - if (ac == null) { - return true; - } else { - return ac.isTrueFor(m.getHopCount()); - } - } - - /** - * Returns true if the given message, using the given connection, is OK - * to send from "from" to "to" host. - * @param from The sending host - * @param to The receiving host - * @param con The connection used by the hosts - * @param m The message to transfer - * @return True if the message is OK to transfer, false is not - */ - public boolean acceptSending(DTNHost from, DTNHost to, Connection con, - Message m) { - if (!checkMcbConditions(from.getComBus(), false)) { - return false; - } - - int myAddr = from.getAddress(); - if (! (checkSimplePolicy(m.getTo(), this.toSendPolicy, myAddr) && - checkSimplePolicy(m.getFrom(), this.fromSendPolicy, myAddr)) ) { - return false; - } - - if (m.getTo() != to && - !checkHopCountPolicy(m, this.hopCountSendPolicy)){ - return false; - } - - return true; - } - - /** - * Returns true if the given message is OK to receive from "from" to - * "to" host. - * @param from The sending host - * @param to The receiving host - * @param m The message to transfer - * @return True if the message is OK to transfer, false is not - */ - public boolean acceptReceiving(DTNHost from, DTNHost to, Message m) { - if (! checkMcbConditions(to.getComBus(), true)) { - return false; - } - - int myAddr = to.getAddress(); - if (! (checkSimplePolicy(m.getTo(), this.toReceivePolicy,myAddr) && - checkSimplePolicy(m.getFrom(), this.fromReceivePolicy, myAddr)) ) { - return false; - } - - if (m.getTo() != to && - !checkHopCountPolicy(m, this.hopCountReceivePolicy)) { - return false; - } - - return true; - } - -} \ No newline at end of file +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.util; + +import java.util.ArrayList; + +import util.Range; +import util.Tuple; + +import core.ArithmeticCondition; +import core.Connection; +import core.DTNHost; +import core.Message; +import core.ModuleCommunicationBus; +import core.Settings; + +/** + *

Message transfer accepting policy module. Can be used to decide whether + * certain messages should be accepted or not. Shared by a whole node group, but + * uses the module communication bus of each node in question.

+ *

Supports 3 different modes: "simple policy", Hop Count, and + * ModuleCommunicationBus (MCB) values. With simple policy, hosts that are + * accepted as the source of a message (i.e., the original message sender) when + * receiving a message are listed (comma separated values) using the + * {@link #FROM_RPOLICY_S} setting + * (when sending, using {@link #FROM_SPOLICY_S}) and hosts that are accepted as + * the destination when receiving are listed using {@link #TO_RPOLICY_S} + * (and when sending, using {@link #TO_SPOLICY_S}). By default, any message is + * accepted.

+ * With ModuleCommunicationBus values, the amount of conditions is first defined + * with {@link #NROF_MCBCS_S} and sending/receiving conditions are defined + * as {@link ArithmeticCondition} with {@link #MCBACS_S} or {@link #MCBACR_S} + * and the ModuleCommuncationBus IDs where to get values from to use with the + * condition with {@link #MCBCVS_S} and {@link #MCBCVR_S}.

+ *

The MCB conditions are checked first, and if none of them match, + * simple policy conditions are checked. If they don't exists, + * or one of them matches, hop count policy is checked. If that doesn't exist + * or matches to message's hop count, transfer is accepted. Otherwise transfer + * is denied. + *

+ * @author Ari + */ +public class MessageTransferAcceptPolicy { + + /** Namespace for all "Message Transfer Accept policy" settings ({@value})*/ + public static final String MTA_POLICY_NS = "mtaPolicy"; + + /** Number of Module Communication Bus Conditions -setting id ({@value}). + * Two comma separated values. Defines the number of receiving and number of + * sending conditions to read from the settings. */ + public static final String NROF_MCBCS_S = "nrofMCBACs"; + + /** Module Communication Bus Arithmetic Condition for Receiving -setting id + * ({@value}). {@link ArithmeticCondition}. Defines one arithmetic condition + * to use for receiving messages. */ + public static final String MCBACR_S = "MCBRcondition"; + /** Module Communication Bus Arithmetic Condition for Sending -setting id + * ({@value}). {@link ArithmeticCondition}. */ + public static final String MCBACS_S = "MCBScondition"; + + /** Module Communication Bus Condition Value for Receiving -setting id + * ({@value}). String. Defines the ID to use with the receiving + * condition. */ + public static final String MCBCVR_S = "MCBRvalue"; + /** Module Communication Bus Condition Value for Sending -setting id + * ({@value}). String. Defines the ID to use with the sending + * condition. */ + public static final String MCBCVS_S = "MCBSvalue"; + + /** The valued used in to-policy to refer to this host ({@value}) */ + public static final int TO_ME_VALUE = -1; + + /** Simple-policy accept-to -setting id ({@value}). Integer list. + * Defines the addresses of the hosts accepted as the destination of a + * message when receiving messages. Special value {@link #TO_ME_VALUE} + * refers to this host. */ + public static final String TO_RPOLICY_S = "toReceivePolicy"; + + /** Simple-policy accept-from -setting id ({@value}). Integer list. + * Defines the addresses of the hosts accepted as the source of a + * message when receiving messages. Special value {@link #TO_ME_VALUE} + * refers to this host. */ + public static final String FROM_RPOLICY_S = "fromReceivePolicy"; + + /** Simple-policy accept-to -setting id ({@value}). Integer list. + * Defines the addresses of the hosts accepted as the destination of a + * message when sending messages. Special value {@link #TO_ME_VALUE} refers + * to this host (but doesn't usually make much sense here). */ + public static final String TO_SPOLICY_S = "toSendPolicy"; + + /**

Simple-policy accept-from -setting id ({@value}). Integer list. + * Defines the addresses of the hosts accepted as the source of a + * message when sending messages. Special value {@link #TO_ME_VALUE} refers + * to this host.

+ *

Note: if this setting is defined and the {@link #TO_ME_VALUE} + * is NOT listed, the hosts own messages are not sent anywhere.

*/ + public static final String FROM_SPOLICY_S = "fromSendPolicy"; + + /** Hop count forwarding receive policy -setting id ({@value}). + * {@link ArithmeticCondition}. Defines condition for the message hop + * count; if the condition does not match, the message is rejected, + * unless it is destined to this node. */ + public static final String HOPCOUNT_RPOLICY_S = "hopCountReceivePolicy"; + /** Hop count forwarding send policy -setting id ({@value}). + * {@link ArithmeticCondition}. Defines condition for the message hop + * count; if the condition does not match, the message is not offered + * to other nodes, unless it would be delivered to the final destination. */ + public static final String HOPCOUNT_SPOLICY_S = "hopCountSendPolicy"; + + private ArrayList> recvConditions = null; + private ArrayList> sendConditions = null; + + private Range[] toSendPolicy = null; + private Range[] fromSendPolicy = null; + private Range[] toReceivePolicy = null; + private Range[] fromReceivePolicy = null; + private ArithmeticCondition hopCountSendPolicy = null; + private ArithmeticCondition hopCountReceivePolicy = null; + + public MessageTransferAcceptPolicy(Settings nsSettings) { + Settings s; + + if (! nsSettings.contains(MTA_POLICY_NS)) { + return; /* no (or "default") policy */ + } + + s = new Settings(nsSettings.getSetting(MTA_POLICY_NS)); + addMCBCs(s); + + if (s.contains(TO_SPOLICY_S)) { + this.toSendPolicy = s.getCsvRanges(TO_SPOLICY_S); + } + if (s.contains(FROM_SPOLICY_S)) { + this.fromSendPolicy = s.getCsvRanges(FROM_SPOLICY_S); + } + if (s.contains(TO_RPOLICY_S)) { + this.toReceivePolicy = s.getCsvRanges(TO_RPOLICY_S); + } + if (s.contains(FROM_RPOLICY_S)) { + this.fromReceivePolicy = s.getCsvRanges(FROM_RPOLICY_S); + } + if (s.contains(HOPCOUNT_SPOLICY_S)) { + hopCountSendPolicy = s.getCondition(HOPCOUNT_SPOLICY_S); + } + if (s.contains(HOPCOUNT_RPOLICY_S)) { + hopCountReceivePolicy = s.getCondition(HOPCOUNT_RPOLICY_S); + } + } + + /** + * Adds MessageCommunicationBus Conditions + * @param s Settings where the conditions are read from + */ + private void addMCBCs(Settings s) { + if (!s.contains(NROF_MCBCS_S)) { + return; /* no transfer policy defined */ + } + + int[] nrof = s.getCsvInts(NROF_MCBCS_S); + if (nrof[0] > 0) { /* create lists only if needed */ + this.recvConditions = + new ArrayList>(); + } + if (nrof[1] > 0) { + this.sendConditions = + new ArrayList>(); + } + + addConditions(s, MCBACR_S, MCBCVR_S, this.recvConditions, nrof[0]); + addConditions(s, MCBACS_S, MCBCVS_S, this.sendConditions, nrof[1]); + } + + /** + * Read conditions from the settings and add them to the given list + * @param s The settings object + * @param cPrefix Condition setting prefix + * @param vPrefix Value setting prefix + * @param list The list to add conditions + * @param nrof The number of settings to read + */ + private void addConditions(Settings s, String cPrefix, String vPrefix, + ArrayList> list, + int nrof) { + for (int i=1; i<=nrof; i++) { + ArithmeticCondition ac = s.getCondition(cPrefix + i); + String mcbValue = s.getSetting(vPrefix + i); + list.add(new Tuple(mcbValue, ac)); + } + } + + /** + * Checks all the Module Communication Bus conditions and returns false + * if at least one of them failed. + * @param mcb The module communication bus to use + * @param receiving Should check using the receiving conditions list; + * if false, the sending conditions list is used + * @return true if all conditions evaluated to true + */ + private boolean checkMcbConditions(ModuleCommunicationBus mcb, + boolean receiving) { + ArrayList> list = + (receiving ? this.recvConditions : this.sendConditions); + + if (list == null) { + return true; + } + + for (Tuple t : list) { + if (!mcb.containsProperty(t.getKey())) { + continue; /* no value in the bus; can't fail condition */ + } + if (t.getValue().isTrueFor(mcb.getDouble(t.getKey(), 0))){ + return false; + } + } + + return true; + } + + /** + * Checks if the host's address is contained in the policy list + * (or {@value #TO_ME_VALUE} is contained and the address matches to + * thisHost parameter) + * @param host The hosts whose address to check + * @param policy The list of accepted addresses + * @param thisHost The address of this host + * @return True if the address was in the policy list, or the policy list + * was null + */ + private boolean checkSimplePolicy(DTNHost host, Range [] policy, + int thisHost) { + int address; + + if (policy == null) { + return true; + } + + address = host.getAddress(); + + for (Range r : policy) { + if (r.isInRange(TO_ME_VALUE) && address == thisHost) { + return true; + } + else if (r.isInRange(address)) { + return true; + } + } + return false; + } + + /** + * Checks the given messages hop count against the given policy arithmetic + * condition + * @param m The message whose hop count is checked + * @param ac The policy arithmetic condition + * @return True if the condition is null or the hop count matches to the + * condition, false otherwise + */ + private boolean checkHopCountPolicy(Message m, ArithmeticCondition ac) { + if (ac == null) { + return true; + } else { + return ac.isTrueFor(m.getHopCount()); + } + } + + /** + * Returns true if the given message, using the given connection, is OK + * to send from "from" to "to" host. + * @param from The sending host + * @param to The receiving host + * @param con The connection used by the hosts + * @param m The message to transfer + * @return True if the message is OK to transfer, false is not + */ + public boolean acceptSending(DTNHost from, DTNHost to, Connection con, + Message m) { + if (!checkMcbConditions(from.getComBus(), false)) { + return false; + } + + int myAddr = from.getAddress(); + if (! (checkSimplePolicy(m.getTo(), this.toSendPolicy, myAddr) && + checkSimplePolicy(m.getFrom(), this.fromSendPolicy, myAddr)) ) { + return false; + } + + if (m.getTo() != to && + !checkHopCountPolicy(m, this.hopCountSendPolicy)){ + return false; + } + + return true; + } + + /** + * Returns true if the given message is OK to receive from "from" to + * "to" host. + * @param from The sending host + * @param to The receiving host + * @param m The message to transfer + * @return True if the message is OK to transfer, false is not + */ + public boolean acceptReceiving(DTNHost from, DTNHost to, Message m) { + if (! checkMcbConditions(to.getComBus(), true)) { + return false; + } + + int myAddr = to.getAddress(); + if (! (checkSimplePolicy(m.getTo(), this.toReceivePolicy,myAddr) && + checkSimplePolicy(m.getFrom(), this.fromReceivePolicy, myAddr)) ) { + return false; + } + + if (m.getTo() != to && + !checkHopCountPolicy(m, this.hopCountReceivePolicy)) { + return false; + } + + return true; + } + +} diff --git a/routing/util/RoutingInfo.java b/routing/util/RoutingInfo.java index 00c35b35d..efba123c8 100644 --- a/routing/util/RoutingInfo.java +++ b/routing/util/RoutingInfo.java @@ -1,66 +1,66 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package routing.util; - +package routing.util; + import java.util.ArrayList; import java.util.List; - -/** - * Class for storing routing related information in a tree form for - * user interface(s). - */ -public class RoutingInfo { - private String text; - private List moreInfo = null; - - /** - * Creates a routing info based on a text. - * @param infoText The text of the info - */ - public RoutingInfo(String infoText) { - this.text = infoText; - } - - /** - * Creates a routing info based on any object. Object's - * toString() method's output is used as the info text. - * @param o The object this info is based on - */ - public RoutingInfo(Object o) { - this.text = o.toString(); - } - - /** - * Adds child info object for this routing info. - * @param info The info object to add. - */ - public void addMoreInfo(RoutingInfo info) { - if (this.moreInfo == null) { // lazy creation - this.moreInfo = new ArrayList(); - } - this.moreInfo.add(info); - } - - /** - * Returns the child routing infos of this info. - * @return The children of this info or an empty list if this info - * doesn't have any children. - */ - public List getMoreInfo() { - if (this.moreInfo == null) { - return new ArrayList(0); - } - return this.moreInfo; - } - - /** - * Returns the info text of this routing info. - * @return The info text - */ - public String toString() { - return this.text; - } - -} + +/** + * Class for storing routing related information in a tree form for + * user interface(s). + */ +public class RoutingInfo { + private String text; + private List moreInfo = null; + + /** + * Creates a routing info based on a text. + * @param infoText The text of the info + */ + public RoutingInfo(String infoText) { + this.text = infoText; + } + + /** + * Creates a routing info based on any object. Object's + * toString() method's output is used as the info text. + * @param o The object this info is based on + */ + public RoutingInfo(Object o) { + this.text = o.toString(); + } + + /** + * Adds child info object for this routing info. + * @param info The info object to add. + */ + public void addMoreInfo(RoutingInfo info) { + if (this.moreInfo == null) { // lazy creation + this.moreInfo = new ArrayList(); + } + this.moreInfo.add(info); + } + + /** + * Returns the child routing infos of this info. + * @return The children of this info or an empty list if this info + * doesn't have any children. + */ + public List getMoreInfo() { + if (this.moreInfo == null) { + return new ArrayList(0); + } + return this.moreInfo; + } + + /** + * Returns the info text of this routing info. + * @return The info text + */ + public String toString() { + return this.text; + } + +} diff --git a/test/AbstractRouterTest.java b/test/AbstractRouterTest.java index 59bd6ffae..aa91da943 100644 --- a/test/AbstractRouterTest.java +++ b/test/AbstractRouterTest.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import java.util.ArrayList; import java.util.List; @@ -14,85 +14,85 @@ import core.MessageListener; import core.NetworkInterface; import core.SimClock; - -/** - * Superclass for router tests. Sets up the environment by creating - * multiple hosts with router set by {@link #setRouterProto(MessageRouter)} - */ -public abstract class AbstractRouterTest extends TestCase { - protected MessageChecker mc; - protected TestUtils utils; - protected static TestSettings ts = new TestSettings(); - - protected static final int BUFFER_SIZE = 100; - protected static final int TRANSMIT_SPEED = 10; - protected SimClock clock; - - protected Coord c0 = new Coord(0,0); - protected Coord farAway = new Coord(100000,100000); - protected static final Coord disconnectLocation = new Coord(900000,900000); + +/** + * Superclass for router tests. Sets up the environment by creating + * multiple hosts with router set by {@link #setRouterProto(MessageRouter)} + */ +public abstract class AbstractRouterTest extends TestCase { + protected MessageChecker mc; + protected TestUtils utils; + protected static TestSettings ts = new TestSettings(); + + protected static final int BUFFER_SIZE = 100; + protected static final int TRANSMIT_SPEED = 10; + protected SimClock clock; + + protected Coord c0 = new Coord(0,0); + protected Coord farAway = new Coord(100000,100000); + protected static final Coord disconnectLocation = new Coord(900000,900000); protected DTNHost h0; - protected DTNHost h1; - protected DTNHost h2; - protected DTNHost h3; - protected DTNHost h4; - protected DTNHost h5; - protected DTNHost h6; - protected static final String msgId1 = "MSG_ID1"; - protected static final String msgId2 = "MSG_ID2"; - protected static final String msgId3 = "MSG_ID3"; - protected static final String msgId4 = "MSG_ID4"; - protected static final String msgId5 = "MSG_ID5"; - - protected MessageRouter routerProto; - - protected void setUp() throws Exception { - super.setUp(); + protected DTNHost h1; + protected DTNHost h2; + protected DTNHost h3; + protected DTNHost h4; + protected DTNHost h5; + protected DTNHost h6; + protected static final String msgId1 = "MSG_ID1"; + protected static final String msgId2 = "MSG_ID2"; + protected static final String msgId3 = "MSG_ID3"; + protected static final String msgId4 = "MSG_ID4"; + protected static final String msgId5 = "MSG_ID5"; + + protected MessageRouter routerProto; + + protected void setUp() throws Exception { + super.setUp(); this.mc = new MessageChecker(); - mc.reset(); - this.clock = SimClock.getInstance(); - clock.setTime(0); - - List ml = new ArrayList(); + mc.reset(); + this.clock = SimClock.getInstance(); + clock.setTime(0); + + List ml = new ArrayList(); ml.add(mc); ts.setNameSpace(TestUtils.IFACE_NS); ts.putSetting(NetworkInterface.TRANSMIT_SPEED_S, ""+TRANSMIT_SPEED); - - this.utils = new TestUtils(null,ml,ts); - this.utils.setMessageRouterProto(routerProto); + + this.utils = new TestUtils(null,ml,ts); + this.utils.setMessageRouterProto(routerProto); core.NetworkInterface.reset(); core.DTNHost.reset(); - this.h0 = utils.createHost(c0, "h0"); - this.h1 = utils.createHost(c0, "h1"); - this.h2 = utils.createHost(c0, "h2"); - this.h3 = utils.createHost(c0, "h3"); - this.h4 = utils.createHost(c0, "h4"); - this.h5 = utils.createHost(c0, "h5"); - this.h6 = utils.createHost(c0, "h6"); - } - - protected void setRouterProto(MessageRouter r) { - this.routerProto = r; - } - - /** - * Checks that mc contains only nrof create-events and nothing else - * @param nrof how many creates to expect - */ - protected void checkCreates(int nrof) { - for (int i=0; i cl = new Vector(); - cl.add(r); - - utils = new TestUtils(cl, null, ts); - } - - private void generateConnections() { - Coord c1 = new Coord(0,0); - Coord c2 = new Coord(1,0); - Coord c3 = new Coord(2,0); - Coord c4 = new Coord(0,2); - - utils.setTransmitRange(2); - DTNHost h1 = utils.createHost(c1,"h1"); - DTNHost h2 = utils.createHost(c2,"h2"); - DTNHost h3 = utils.createHost(c3,"h3"); - DTNHost h4 = utils.createHost(c4,"h4"); - - h1.connect(h2); - h2.connect(h3); - // h1--h2--h3 - - h2.setLocation(new Coord(1,10)); - h2.update(true); - // h2 - // h1 h3 - - h2.setLocation(c2); - h2.connect(h3); // reconnect - // h1 h2--h3 - - h1.connect(h4); - - c4.translate(-5, 0); - h1.update(true); // disconnect h1-h4 - c4.translate(5, 0); - h1.connect(h4); // reconnect h1-h4 - } - - public void testDone() throws IOException { - BufferedReader reader; + + private static final int NROF = 3; + + public void setUp() throws IOException { + TestSettings ts = new TestSettings(); + outFile = File.createTempFile("adjgvtest", ".tmp"); + outFile.deleteOnExit(); + + ts.putSetting("AdjacencyGraphvizReport.output", outFile.getAbsolutePath()); + ts.putSetting("AdjacencyGraphvizReport.interval" , ""); + r = new AdjacencyGraphvizReport(); + Vector cl = new Vector(); + cl.add(r); + + utils = new TestUtils(cl, null, ts); + } + + private void generateConnections() { + Coord c1 = new Coord(0,0); + Coord c2 = new Coord(1,0); + Coord c3 = new Coord(2,0); + Coord c4 = new Coord(0,2); + + utils.setTransmitRange(2); + DTNHost h1 = utils.createHost(c1,"h1"); + DTNHost h2 = utils.createHost(c2,"h2"); + DTNHost h3 = utils.createHost(c3,"h3"); + DTNHost h4 = utils.createHost(c4,"h4"); + + h1.connect(h2); + h2.connect(h3); + // h1--h2--h3 + + h2.setLocation(new Coord(1,10)); + h2.update(true); + // h2 + // h1 h3 + + h2.setLocation(c2); + h2.connect(h3); // reconnect + // h1 h2--h3 + + h1.connect(h4); + + c4.translate(-5, 0); + h1.update(true); // disconnect h1-h4 + c4.translate(5, 0); + h1.connect(h4); // reconnect h1-h4 + } + + public void testDone() throws IOException { + BufferedReader reader; List lines = new ArrayList(); - - generateConnections(); - r.done(); - - reader = new BufferedReader(new FileReader(outFile)); - - // check the first line of output - assertEquals("graph " + AdjacencyGraphvizReport.GRAPH_NAME + + + generateConnections(); + r.done(); + + reader = new BufferedReader(new FileReader(outFile)); + + // check the first line of output + assertEquals("graph " + AdjacencyGraphvizReport.GRAPH_NAME + " {", reader.readLine()); - + for (int i=0; i li = new ArrayList(); - li.add(ni); - - ModuleCommunicationBus comBus = new ModuleCommunicationBus(); - h[i] = new TestDTNHost(li,comBus, testSettings); - m[i] = new Message(h[0], h[i],""+i, size[i]); - } - - con(h[0], h[1]); - con(h[0], h[2]); - con(h[1], h[3]); - con(h[2], h[4]); - con(h[3], h[4]); - - c[0].startTransfer(h[0], m[0]); - c[1].startTransfer(h[0], m[1]); - c[2].startTransfer(h[1], m[2]); - conCount = 3; - } - - private void con(DTNHost from, DTNHost to) { - c[index] = new CBRConnection(from, from.getInterfaces().get(0), to, to.getInterfaces().get(0), speed[index]); - index++; - } - - public void testIsInitiator() { - assertTrue(c[0].isInitiator(h[0])); - assertFalse(c[0].isInitiator(h[1])); - assertFalse(c[0].isInitiator(h[2])); - assertTrue(c[3].isInitiator(h[2])); - } - - public void testStartTransfer() { - assertTrue(h[1].recvFrom == h[0]); - assertTrue(h[1].recvMessage.getId().equals(m[0].getId())); - assertTrue(h[2].recvFrom == h[0]); - assertTrue(h[2].recvMessage.getId().equals(m[1].getId())); - } - - public void testAbortTransfer() { - assertTrue(h[1].abortedId == null); - assertFalse(c[0].isMessageTransferred()); - - c[0].abortTransfer(); - - assertTrue(h[1].abortedId != null); - assertTrue(h[1].abortedId.equals(m[0].getId())); - assertTrue(c[0].isMessageTransferred()); - } - - public void testGetTransferDoneTime() { - double doneTime; - - doneTime = START_TIME + (1.0 * m[0].getSize()) / speed[0]; - assertEquals(doneTime, c[0].getTransferDoneTime()); - - doneTime = START_TIME + (1.0 * m[1].getSize()) / speed[1]; - assertEquals(doneTime, c[1].getTransferDoneTime()); - } - - public void testGetRemainingByteCount() { - double STEP = 0.1; - int transferred; - - assertEquals(size[0], c[0].getRemainingByteCount()); - assertEquals(size[1], c[1].getRemainingByteCount()); - - clock.setTime(START_TIME + STEP); - for (int i=0; i li = new ArrayList(); + li.add(ni); + + ModuleCommunicationBus comBus = new ModuleCommunicationBus(); + h[i] = new TestDTNHost(li,comBus, testSettings); + m[i] = new Message(h[0], h[i],""+i, size[i]); + } + + con(h[0], h[1]); + con(h[0], h[2]); + con(h[1], h[3]); + con(h[2], h[4]); + con(h[3], h[4]); + + c[0].startTransfer(h[0], m[0]); + c[1].startTransfer(h[0], m[1]); + c[2].startTransfer(h[1], m[2]); + conCount = 3; + } + + private void con(DTNHost from, DTNHost to) { + c[index] = new CBRConnection(from, from.getInterfaces().get(0), to, to.getInterfaces().get(0), speed[index]); + index++; + } + + public void testIsInitiator() { + assertTrue(c[0].isInitiator(h[0])); + assertFalse(c[0].isInitiator(h[1])); + assertFalse(c[0].isInitiator(h[2])); + assertTrue(c[3].isInitiator(h[2])); + } + + public void testStartTransfer() { + assertTrue(h[1].recvFrom == h[0]); + assertTrue(h[1].recvMessage.getId().equals(m[0].getId())); + assertTrue(h[2].recvFrom == h[0]); + assertTrue(h[2].recvMessage.getId().equals(m[1].getId())); + } + + public void testAbortTransfer() { + assertTrue(h[1].abortedId == null); + assertFalse(c[0].isMessageTransferred()); + + c[0].abortTransfer(); + + assertTrue(h[1].abortedId != null); + assertTrue(h[1].abortedId.equals(m[0].getId())); + assertTrue(c[0].isMessageTransferred()); + } + + public void testGetTransferDoneTime() { + double doneTime; + + doneTime = START_TIME + (1.0 * m[0].getSize()) / speed[0]; + assertEquals(doneTime, c[0].getTransferDoneTime()); + + doneTime = START_TIME + (1.0 * m[1].getSize()) / speed[1]; + assertEquals(doneTime, c[1].getTransferDoneTime()); + } + + public void testGetRemainingByteCount() { + double STEP = 0.1; + int transferred; + + assertEquals(size[0], c[0].getRemainingByteCount()); + assertEquals(size[1], c[1].getRemainingByteCount()); + + clock.setTime(START_TIME + STEP); + for (int i=0; i cl = new Vector(); - cl.add(ctr); - cl.add(ictr); - - TestUtils utils = new TestUtils(cl, null, ts); - generateConnections(utils); - ctr.done(); - ictr.done(); - ctReader = new BufferedReader(new FileReader(outFile)); - ictReader = new BufferedReader(new FileReader(iOutFile)); - - } - - private void generateConnections(TestUtils utils) { - Coord c1 = new Coord(0,0); - Coord c2 = new Coord(1,0); - Coord c3 = new Coord(2,0); - - utils.setTransmitRange(3); // make sure everyone can connect - DTNHost h1 = utils.createHost(c1); - DTNHost h2 = utils.createHost(c2); - DTNHost h3 = utils.createHost(c3); - - h1.connect(h2); - - clock.advance(1.0); - h2.connect(h3); - - clock.advance(2.0); - h2.setLocation(new Coord(10,10)); - h1.update(true); // disconnect h1-h2 - h3.update(true); // disconnect h2-h3 (from h3) - - clock.advance(3.0); - h2.setLocation(c2); - h3.connect(h2); // reconnect the other way - h2.setLocation(new Coord(10,10)); - clock.advance(3.5); - h3.update(true); // disconnect - - clock.advance(10); - h3.setLocation(c2); - h3.connect(h1); // con h3--h1 - clock.advance(6); - h1.setLocation(new Coord(-10,0)); - h1.update(true); // disconnect 6 sec connection - } - - public void testReport() throws IOException { - String[] ctValues = {"0.0 0", "1.0 0", "2.0 1", "3.0 2", "4.0 0", - "5.0 0", "6.0 1", "7.0 0"}; - String[] ictValues = {"0.0 0", "1.0 0", "2.0 0", "3.0 1", - "4.0 0"}; - - this.setUpWithGranularity(1.0); - checkValues(ctValues, ictValues); - } - - private void checkValues(String[] ctValues, String[] ictValues) - throws IOException { - for (String value : ctValues) { - assertEquals(value,ctReader.readLine()); - } - assertEquals(null,ctReader.readLine()); // no more times left - - for (String value : ictValues) { - assertEquals(value,ictReader.readLine()); - } - assertEquals(null,ictReader.readLine()); - } - - public void testGranularity2() throws IOException { - String[] ctValues = {"0.0 0", "2.0 3", "4.0 0", - "6.0 1", "8.0 0"}; - String[] ictValues = {"0.0 0", "2.0 1", "4.0 0"}; - - this.setUpWithGranularity(2.0); - checkValues(ctValues, ictValues); - } - - - public void testGranularity10() throws IOException { - this.setUpWithGranularity(10.0); - - assertEquals("0.0 4",ctReader.readLine()); - assertEquals("10.0 0",ctReader.readLine()); - assertEquals(null,ctReader.readLine()); - } - - public void testGanularity05() throws IOException { - String[] ctValues = {"0.0 0", "0.5 0", "1.0 0", "1.5 0", - "2.0 1", "2.5 0", "3.0 1", "3.5 1", "4.0 0", - "4.5 0", "5.0 0", "5.5 0", "6.0 1", "6.5 0"}; - String[] ictValues = {"0.0 0", "0.5 0", "1.0 0", "1.5 0", - "2.0 0", "2.5 0", "3.0 1", "3.5 0"}; - - this.setUpWithGranularity(0.5); - checkValues(ctValues, ictValues); - } - -} + +/** + * Test cases for ContactTimes & InterContactTimesReports. + */ +public class ContactTimesReportTest extends TestCase { + private BufferedReader ctReader; + private BufferedReader ictReader; + + private SimClock clock; + private final static String SET_PREFIX = "ContactTimesReport."; + private final static String I_SET_PREFIX = "InterContactTimesReport."; + + private void setUpWithGranularity(double gran) throws IOException { + ContactTimesReport ctr; + InterContactTimesReport ictr; + TestSettings ts = new TestSettings(); + + File outFile = File.createTempFile("cttest", ".tmp"); + File iOutFile = File.createTempFile("icttest", ".tmp"); + outFile.deleteOnExit(); + iOutFile.deleteOnExit(); + + ts.putSetting(SET_PREFIX + Report.OUTPUT_SETTING, + outFile.getAbsolutePath()); + ts.putSetting(SET_PREFIX + Report.INTERVAL_SETTING , ""); + ts.putSetting(SET_PREFIX + ContactTimesReport.GRANULARITY, gran+""); + + ts.putSetting(I_SET_PREFIX + Report.OUTPUT_SETTING, + iOutFile.getAbsolutePath()); + ts.putSetting(I_SET_PREFIX + Report.INTERVAL_SETTING , ""); + ts.putSetting(I_SET_PREFIX + ContactTimesReport.GRANULARITY, gran+""); + + clock = SimClock.getInstance(); + + ctr = new ContactTimesReport(); + ictr = new InterContactTimesReport(); + + Vector cl = new Vector(); + cl.add(ctr); + cl.add(ictr); + + TestUtils utils = new TestUtils(cl, null, ts); + generateConnections(utils); + ctr.done(); + ictr.done(); + ctReader = new BufferedReader(new FileReader(outFile)); + ictReader = new BufferedReader(new FileReader(iOutFile)); + + } + + private void generateConnections(TestUtils utils) { + Coord c1 = new Coord(0,0); + Coord c2 = new Coord(1,0); + Coord c3 = new Coord(2,0); + + utils.setTransmitRange(3); // make sure everyone can connect + DTNHost h1 = utils.createHost(c1); + DTNHost h2 = utils.createHost(c2); + DTNHost h3 = utils.createHost(c3); + + h1.connect(h2); + + clock.advance(1.0); + h2.connect(h3); + + clock.advance(2.0); + h2.setLocation(new Coord(10,10)); + h1.update(true); // disconnect h1-h2 + h3.update(true); // disconnect h2-h3 (from h3) + + clock.advance(3.0); + h2.setLocation(c2); + h3.connect(h2); // reconnect the other way + h2.setLocation(new Coord(10,10)); + clock.advance(3.5); + h3.update(true); // disconnect + + clock.advance(10); + h3.setLocation(c2); + h3.connect(h1); // con h3--h1 + clock.advance(6); + h1.setLocation(new Coord(-10,0)); + h1.update(true); // disconnect 6 sec connection + } + + public void testReport() throws IOException { + String[] ctValues = {"0.0 0", "1.0 0", "2.0 1", "3.0 2", "4.0 0", + "5.0 0", "6.0 1", "7.0 0"}; + String[] ictValues = {"0.0 0", "1.0 0", "2.0 0", "3.0 1", + "4.0 0"}; + + this.setUpWithGranularity(1.0); + checkValues(ctValues, ictValues); + } + + private void checkValues(String[] ctValues, String[] ictValues) + throws IOException { + for (String value : ctValues) { + assertEquals(value,ctReader.readLine()); + } + assertEquals(null,ctReader.readLine()); // no more times left + + for (String value : ictValues) { + assertEquals(value,ictReader.readLine()); + } + assertEquals(null,ictReader.readLine()); + } + + public void testGranularity2() throws IOException { + String[] ctValues = {"0.0 0", "2.0 3", "4.0 0", + "6.0 1", "8.0 0"}; + String[] ictValues = {"0.0 0", "2.0 1", "4.0 0"}; + + this.setUpWithGranularity(2.0); + checkValues(ctValues, ictValues); + } + + + public void testGranularity10() throws IOException { + this.setUpWithGranularity(10.0); + + assertEquals("0.0 4",ctReader.readLine()); + assertEquals("10.0 0",ctReader.readLine()); + assertEquals(null,ctReader.readLine()); + } + + public void testGanularity05() throws IOException { + String[] ctValues = {"0.0 0", "0.5 0", "1.0 0", "1.5 0", + "2.0 1", "2.5 0", "3.0 1", "3.5 1", "4.0 0", + "4.5 0", "5.0 0", "5.5 0", "6.0 1", "6.5 0"}; + String[] ictValues = {"0.0 0", "0.5 0", "1.0 0", "1.5 0", + "2.0 0", "2.5 0", "3.0 1", "3.5 0"}; + + this.setUpWithGranularity(0.5); + checkValues(ctValues, ictValues); + } + +} diff --git a/test/CoordTest.java b/test/CoordTest.java index 593fb9dc9..75ecaf000 100644 --- a/test/CoordTest.java +++ b/test/CoordTest.java @@ -1,31 +1,31 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import junit.framework.TestCase; import core.Coord; - -public class CoordTest extends TestCase { - - public void testHashCode() { - Coord c1 = new Coord(1,1); - Coord c2 = new Coord(1,1); - Coord c3 = new Coord(2,3); - Coord c4 = new Coord(3,2); - Coord c5 = new Coord(-2,-3); - Coord c6 = new Coord(-2,-3); - - assertTrue(c1.hashCode() == c2.hashCode()); - assertTrue(c1.hashCode() != c3.hashCode()); - assertTrue(c3.hashCode() != c4.hashCode()); - assertTrue(c5.hashCode() == c6.hashCode()); - assertTrue(c3.hashCode() != c5.hashCode()); - - c5.translate(1, 1); - assertTrue(c5.hashCode() != c6.hashCode()); - - } - -} + +public class CoordTest extends TestCase { + + public void testHashCode() { + Coord c1 = new Coord(1,1); + Coord c2 = new Coord(1,1); + Coord c3 = new Coord(2,3); + Coord c4 = new Coord(3,2); + Coord c5 = new Coord(-2,-3); + Coord c6 = new Coord(-2,-3); + + assertTrue(c1.hashCode() == c2.hashCode()); + assertTrue(c1.hashCode() != c3.hashCode()); + assertTrue(c3.hashCode() != c4.hashCode()); + assertTrue(c5.hashCode() == c6.hashCode()); + assertTrue(c3.hashCode() != c5.hashCode()); + + c5.translate(1, 1); + assertTrue(c5.hashCode() != c6.hashCode()); + + } + +} diff --git a/test/DijkstraPathFinderTest.java b/test/DijkstraPathFinderTest.java index 41679a0d1..a47d0625f 100644 --- a/test/DijkstraPathFinderTest.java +++ b/test/DijkstraPathFinderTest.java @@ -1,90 +1,90 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import java.util.List; import junit.framework.TestCase; import movement.map.DijkstraPathFinder; import movement.map.MapNode; import core.Coord; - -public class DijkstraPathFinderTest extends TestCase { - private DijkstraPathFinder r; - - private final MapNode n1 = newNode(0,0); - private final MapNode n2 = newNode(10,0); - private final MapNode n3 = newNode(20,0); - private final MapNode n4 = newNode(0,10); - private final MapNode n5 = newNode(10,10); - private final MapNode n6 = newNode(15,10); - private final MapNode n7 = newNode(20,10); - private final MapNode n8 = newNode(25,10); - - protected void setUp() throws Exception { - super.setUp(); - r = new DijkstraPathFinder(null); - createTopology(); - } - - /** - * Creates a topology: - * - * n1-10-n2---10---n3 - * 10 10 / 10 - * n4-10-n5-5-n6-5-n7-5-n8 - */ - private void createTopology() { - n1.addNeighbor(n2); - n1.addNeighbor(n4); - n2.addNeighbor(n1); - n2.addNeighbor(n5); - n2.addNeighbor(n3); - n3.addNeighbor(n2); - n3.addNeighbor(n6); - n3.addNeighbor(n7); - n4.addNeighbor(n1); - n4.addNeighbor(n5); - n5.addNeighbor(n4); - n5.addNeighbor(n2); - n5.addNeighbor(n6); - n6.addNeighbor(n5); - n6.addNeighbor(n3); - n6.addNeighbor(n7); - n7.addNeighbor(n6); - n7.addNeighbor(n3); - n7.addNeighbor(n8); - n8.addNeighbor(n7); - } - - private MapNode newNode(double x, double y) { - return new MapNode(new Coord(x,y)); - } - - public void testPathFinding() { - checkPath(getPath(n1,n1), n1); - checkPath(getPath(n1,n3), n1, n2, n3); - checkPath(getPath(n1,n6), n1, n2, n5, n6); - checkPath(getPath(n5,n3), n5, n6, n3); - checkPath(getPath(n3,n5), n3, n6, n5); - checkPath(getPath(n4,n8), n4, n5, n6, n7, n8); - checkPath(getPath(n8,n4), n8, n7, n6, n5, n4); - } - - private void checkPath(List path, MapNode ... nodes) { - assertEquals(nodes.length,path.size()); - - for (int i=0; i< nodes.length; i++) { - assertEquals((i+1)+"th node was wrong",nodes[i],path.get(i)); - } - } - - private List getPath(MapNode from, MapNode to) { - List path = r.getShortestPath(from, to); - return path; - } - - -} + +public class DijkstraPathFinderTest extends TestCase { + private DijkstraPathFinder r; + + private final MapNode n1 = newNode(0,0); + private final MapNode n2 = newNode(10,0); + private final MapNode n3 = newNode(20,0); + private final MapNode n4 = newNode(0,10); + private final MapNode n5 = newNode(10,10); + private final MapNode n6 = newNode(15,10); + private final MapNode n7 = newNode(20,10); + private final MapNode n8 = newNode(25,10); + + protected void setUp() throws Exception { + super.setUp(); + r = new DijkstraPathFinder(null); + createTopology(); + } + + /** + * Creates a topology: + * + * n1-10-n2---10---n3 + * 10 10 / 10 + * n4-10-n5-5-n6-5-n7-5-n8 + */ + private void createTopology() { + n1.addNeighbor(n2); + n1.addNeighbor(n4); + n2.addNeighbor(n1); + n2.addNeighbor(n5); + n2.addNeighbor(n3); + n3.addNeighbor(n2); + n3.addNeighbor(n6); + n3.addNeighbor(n7); + n4.addNeighbor(n1); + n4.addNeighbor(n5); + n5.addNeighbor(n4); + n5.addNeighbor(n2); + n5.addNeighbor(n6); + n6.addNeighbor(n5); + n6.addNeighbor(n3); + n6.addNeighbor(n7); + n7.addNeighbor(n6); + n7.addNeighbor(n3); + n7.addNeighbor(n8); + n8.addNeighbor(n7); + } + + private MapNode newNode(double x, double y) { + return new MapNode(new Coord(x,y)); + } + + public void testPathFinding() { + checkPath(getPath(n1,n1), n1); + checkPath(getPath(n1,n3), n1, n2, n3); + checkPath(getPath(n1,n6), n1, n2, n5, n6); + checkPath(getPath(n5,n3), n5, n6, n3); + checkPath(getPath(n3,n5), n3, n6, n5); + checkPath(getPath(n4,n8), n4, n5, n6, n7, n8); + checkPath(getPath(n8,n4), n8, n7, n6, n5, n4); + } + + private void checkPath(List path, MapNode ... nodes) { + assertEquals(nodes.length,path.size()); + + for (int i=0; i< nodes.length; i++) { + assertEquals((i+1)+"th node was wrong",nodes[i],path.get(i)); + } + } + + private List getPath(MapNode from, MapNode to) { + List path = r.getShortestPath(from, to); + return path; + } + + +} diff --git a/test/DistanceDelayReportTest.java b/test/DistanceDelayReportTest.java index 7cb2fbc26..04788eeff 100644 --- a/test/DistanceDelayReportTest.java +++ b/test/DistanceDelayReportTest.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -17,69 +17,69 @@ import core.Message; import core.MessageListener; import core.SimClock; - -public class DistanceDelayReportTest extends TestCase { - private SimClock clock; - File outFile; - - private Vector ml; - private DistanceDelayReport r; - private TestUtils utils; - - public void setUp() throws IOException { - final String NS = "DistanceDelayReport."; - TestSettings ts = new TestSettings(); - outFile = File.createTempFile("ddrtest", ".tmp"); - outFile.deleteOnExit(); - - ts.putSetting(NS + "output", outFile.getAbsolutePath()); - ts.putSetting(NS + report.Report.PRECISION_SETTING, "1"); - clock = SimClock.getInstance(); - r = new DistanceDelayReport(); - ml = new Vector(); - ml.add(r); - this.utils = new TestUtils(null, ml, ts); - } - - - public void testMessageTransferred() throws IOException { - DTNHost h1 = utils.createHost(new Coord(0,0)); - DTNHost h2 = utils.createHost(new Coord(2,0)); - DTNHost h3 = utils.createHost(new Coord(0,5)); + +public class DistanceDelayReportTest extends TestCase { + private SimClock clock; + File outFile; + + private Vector ml; + private DistanceDelayReport r; + private TestUtils utils; + + public void setUp() throws IOException { + final String NS = "DistanceDelayReport."; + TestSettings ts = new TestSettings(); + outFile = File.createTempFile("ddrtest", ".tmp"); + outFile.deleteOnExit(); + + ts.putSetting(NS + "output", outFile.getAbsolutePath()); + ts.putSetting(NS + report.Report.PRECISION_SETTING, "1"); + clock = SimClock.getInstance(); + r = new DistanceDelayReport(); + ml = new Vector(); + ml.add(r); + this.utils = new TestUtils(null, ml, ts); + } + + + public void testMessageTransferred() throws IOException { + DTNHost h1 = utils.createHost(new Coord(0,0)); + DTNHost h2 = utils.createHost(new Coord(2,0)); + DTNHost h3 = utils.createHost(new Coord(0,5)); BufferedReader reader; - - Message m1 = new Message(h1, h2, "tst1", 1); - h1.createNewMessage(m1); - clock.advance(1.5); - h1.sendMessage("tst1", h2); - h2.messageTransferred("tst1", h1); - - Message m2 = new Message(h2,h1, "tst2", 1); - h2.createNewMessage(m2); - clock.advance(0.5); - h2.sendMessage("tst2", h1); - h1.messageTransferred("tst2", h2); - + + Message m1 = new Message(h1, h2, "tst1", 1); + h1.createNewMessage(m1); + clock.advance(1.5); + h1.sendMessage("tst1", h2); + h2.messageTransferred("tst1", h1); + + Message m2 = new Message(h2,h1, "tst2", 1); + h2.createNewMessage(m2); + clock.advance(0.5); + h2.sendMessage("tst2", h1); + h1.messageTransferred("tst2", h2); + Message m3 = new Message(h1,h3, "tst3", 1); - h1.createNewMessage(m3); - clock.advance(1.0); - h1.sendMessage("tst3", h2); - h2.messageTransferred("tst3", h1); - h2.sendMessage("tst3", h3); - h3.messageTransferred("tst3", h2); - - r.done(); - - reader = new BufferedReader(new FileReader(outFile)); - - reader.readLine(); // skip headers - reader.readLine(); // skip headers - assertEquals("2.0 1.5 1 tst1",reader.readLine()); - assertEquals("2.0 0.5 1 tst2",reader.readLine()); + h1.createNewMessage(m3); + clock.advance(1.0); + h1.sendMessage("tst3", h2); + h2.messageTransferred("tst3", h1); + h2.sendMessage("tst3", h3); + h3.messageTransferred("tst3", h2); + + r.done(); + + reader = new BufferedReader(new FileReader(outFile)); + + reader.readLine(); // skip headers + reader.readLine(); // skip headers + assertEquals("2.0 1.5 1 tst1",reader.readLine()); + assertEquals("2.0 0.5 1 tst2",reader.readLine()); assertEquals("5.0 1.0 2 tst3",reader.readLine()); - reader.close(); - } - - -} + reader.close(); + } + + +} diff --git a/test/EpidemicRouterTest.java b/test/EpidemicRouterTest.java index 072fc1e71..486b0f1b4 100644 --- a/test/EpidemicRouterTest.java +++ b/test/EpidemicRouterTest.java @@ -1,544 +1,544 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import routing.EpidemicRouter; import routing.MessageRouter; import core.DTNHost; import core.Message; - -/** - * Tests for EpidemicRouter and, due the simple nature of Epidemic router, - * also ActiveRouter in general. - */ -public class EpidemicRouterTest extends AbstractRouterTest { - - private static int TTL = 300; - - @Override - public void setUp() throws Exception { - ts.putSetting(MessageRouter.MSG_TTL_S, ""+TTL); + +/** + * Tests for EpidemicRouter and, due the simple nature of Epidemic router, + * also ActiveRouter in general. + */ +public class EpidemicRouterTest extends AbstractRouterTest { + + private static int TTL = 300; + + @Override + public void setUp() throws Exception { + ts.putSetting(MessageRouter.MSG_TTL_S, ""+TTL); ts.putSetting(MessageRouter.B_SIZE_S, ""+BUFFER_SIZE); - setRouterProto(new EpidemicRouter(ts)); - super.setUp(); - } - - /** - * Tests routing messages between three hosts - */ - public void testRouter() { - // nothing should have happened so far - assertEquals(mc.TYPE_NONE, mc.getLastType()); - - Message m1 = new Message(h1, h3, msgId1, 1); - h1.createNewMessage(m1); - assertTrue(mc.next()); - assertEquals(mc.TYPE_CREATE, mc.getLastType()); - assertEquals(mc.getLastFrom(), h1); - assertEquals(mc.getLastTo(), h3); - - // connect h1-h2-h3 - h1.connect(h2); - h2.connect(h3); - - updateAllNodes(); - clock.advance(2); - updateAllNodes(); - - // should cause relay h1 -> h2 - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - assertFalse(mc.getLastFirstDelivery()); - assertEquals(mc.getLastFrom(), h1); - assertEquals(mc.getLastTo(), h2); - - // should cause relay h2 -> h3 - clock.advance(1); - updateAllNodes(); - - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - assertTrue(mc.getLastFirstDelivery()); - assertEquals(mc.getLastFrom(), h2); - assertEquals(mc.getLastTo(), h3); - // message delivered to recipient - assertFalse(mc.next()); - - - // disconnect all nodes and try to other direction - disconnect(h2); + setRouterProto(new EpidemicRouter(ts)); + super.setUp(); + } + + /** + * Tests routing messages between three hosts + */ + public void testRouter() { + // nothing should have happened so far + assertEquals(mc.TYPE_NONE, mc.getLastType()); + + Message m1 = new Message(h1, h3, msgId1, 1); + h1.createNewMessage(m1); + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + assertEquals(mc.getLastFrom(), h1); + assertEquals(mc.getLastTo(), h3); + + // connect h1-h2-h3 + h1.connect(h2); + h2.connect(h3); + + updateAllNodes(); + clock.advance(2); + updateAllNodes(); + + // should cause relay h1 -> h2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertFalse(mc.getLastFirstDelivery()); + assertEquals(mc.getLastFrom(), h1); + assertEquals(mc.getLastTo(), h2); + + // should cause relay h2 -> h3 + clock.advance(1); + updateAllNodes(); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertTrue(mc.getLastFirstDelivery()); + assertEquals(mc.getLastFrom(), h2); + assertEquals(mc.getLastTo(), h3); + // message delivered to recipient + assertFalse(mc.next()); + + + // disconnect all nodes and try to other direction + disconnect(h2); // create message while not connected - Message m2 = new Message(h3,h1, msgId2, 1); - h3.createNewMessage(m2); - assertTrue(mc.next()); - assertEquals(mc.TYPE_CREATE, mc.getLastType()); - - h1.connect(h2); // reconnect h1-h2 - clock.advance(10); - updateAllNodes(); - assertFalse(mc.next()); // nothing should have happened to messages - - h2.connect(h3); - updateAllNodes(); // now h3 should start forwarding msg to h2 - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - assertEquals(h2, mc.getLastTo()); - assertEquals(h3, mc.getLastFrom()); - assertEquals(msgId2, mc.getLastMsg().getId()); - assertFalse(mc.next()); - - clock.advance(10); - updateAllNodes(); // forwarding msg2 h3->h2 - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - assertEquals(h2, mc.getLastTo()); - assertEquals(h3, mc.getLastFrom()); - assertEquals(msgId2, mc.getLastMsg().getId()); - assertFalse(mc.next()); - - updateAllNodes(); // forwarding msg2 h2->h1 - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - assertFalse(mc.next()); - - clock.advance(10); - updateAllNodes(); // forwarding msg2 h2->h1 - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - assertEquals(h1, mc.getLastTo()); - assertEquals(h2, mc.getLastFrom()); - assertEquals(msgId2, mc.getLastMsg().getId()); - assertTrue(mc.getLastFirstDelivery()); // message delivered to recipient - assertFalse(mc.next()); - } - - /** - * Checks that delivering many messages in a row works - */ + Message m2 = new Message(h3,h1, msgId2, 1); + h3.createNewMessage(m2); + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + + h1.connect(h2); // reconnect h1-h2 + clock.advance(10); + updateAllNodes(); + assertFalse(mc.next()); // nothing should have happened to messages + + h2.connect(h3); + updateAllNodes(); // now h3 should start forwarding msg to h2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(h2, mc.getLastTo()); + assertEquals(h3, mc.getLastFrom()); + assertEquals(msgId2, mc.getLastMsg().getId()); + assertFalse(mc.next()); + + clock.advance(10); + updateAllNodes(); // forwarding msg2 h3->h2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h2, mc.getLastTo()); + assertEquals(h3, mc.getLastFrom()); + assertEquals(msgId2, mc.getLastMsg().getId()); + assertFalse(mc.next()); + + updateAllNodes(); // forwarding msg2 h2->h1 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertFalse(mc.next()); + + clock.advance(10); + updateAllNodes(); // forwarding msg2 h2->h1 + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h1, mc.getLastTo()); + assertEquals(h2, mc.getLastFrom()); + assertEquals(msgId2, mc.getLastMsg().getId()); + assertTrue(mc.getLastFirstDelivery()); // message delivered to recipient + assertFalse(mc.next()); + } + + /** + * Checks that delivering many messages in a row works + */ public void testManyMessages() { - - Message m1 = new Message(h1,h2, msgId1, 1); + + Message m1 = new Message(h1,h2, msgId1, 1); h1.createNewMessage(m1); - Message m2 = new Message(h1,h2, msgId2, 1); - h1.createNewMessage(m2); - mc.reset(); - - h1.connect(h2); + Message m2 = new Message(h1,h2, msgId2, 1); + h1.createNewMessage(m2); + mc.reset(); + + h1.connect(h2); updateAllNodes(); // h1 should start transfer assertTrue(mc.next()); assertEquals(mc.TYPE_START, mc.getLastType()); assertFalse(mc.next()); - - clock.advance(10); + + clock.advance(10); updateAllNodes(); - - /* h1 should have delivered the msg & start next transfer */ - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); + + /* h1 should have delivered the msg & start next transfer */ + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); assertEquals(h2, mc.getLastTo()); assertTrue(mc.next()); assertEquals(mc.TYPE_START, mc.getLastType()); assertFalse(mc.next()); // nothing more happened so far - - clock.advance(10); - updateAllNodes(); // h1 should finish relaying the msg - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - assertEquals(h2, mc.getLastTo()); - - assertFalse(mc.next()); - } - - /** - * Tests that messages that can be delivered right a way are delivered first - */ - public void testDeliverableMessageExchange() { + + clock.advance(10); + updateAllNodes(); // h1 should finish relaying the msg + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h2, mc.getLastTo()); + + assertFalse(mc.next()); + } + + /** + * Tests that messages that can be delivered right a way are delivered first + */ + public void testDeliverableMessageExchange() { Message m1 = new Message(h1,h3, "Dummy1", 1); - h1.createNewMessage(m1); + h1.createNewMessage(m1); Message m2 = new Message(h1,h3, "A_Dummy2", 1); - h1.createNewMessage(m2); + h1.createNewMessage(m2); Message m3 = new Message(h1,h2, msgId1, 1); - h1.createNewMessage(m3); - - Message m4 = new Message(h2,h3, "Dummy3", 1); - h2.createNewMessage(m4); + h1.createNewMessage(m3); + + Message m4 = new Message(h2,h3, "Dummy3", 1); + h2.createNewMessage(m4); Message m5 = new Message(h2,h1, msgId2, 1); - h2.createNewMessage(m5); + h2.createNewMessage(m5); Message m6 = new Message(h2,h3, "Dummy4", 1); - h2.createNewMessage(m6); - - checkCreates(6); - - h1.connect(h2); - updateAllNodes(); - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); // starts h1->h2 msgId1 - assertEquals(h2, mc.getLastTo()); - assertEquals(msgId1, mc.getLastMsg().getId()); - - clock.advance(10); - updateAllNodes(); - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); // finished delivery - - // should also start delivery of msgId2 from h2 to h1 - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - assertEquals(msgId2, mc.getLastMsg().getId()); - assertEquals(h1, mc.getLastTo()); - - } - - /** - * Tests aborting transfer when connections is disconnected during the - * transfer - */ + h2.createNewMessage(m6); + + checkCreates(6); + + h1.connect(h2); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); // starts h1->h2 msgId1 + assertEquals(h2, mc.getLastTo()); + assertEquals(msgId1, mc.getLastMsg().getId()); + + clock.advance(10); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); // finished delivery + + // should also start delivery of msgId2 from h2 to h1 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(msgId2, mc.getLastMsg().getId()); + assertEquals(h1, mc.getLastTo()); + + } + + /** + * Tests aborting transfer when connections is disconnected during the + * transfer + */ public void testMessageRelayAbort() { - Message m1 = new Message(h1,h2, msgId1, BUFFER_SIZE); - h1.createNewMessage(m1); - checkCreates(1); - - h1.connect(h2); - updateAllNodes(); - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - assertFalse(mc.next()); - clock.advance(1); - updateAllNodes(); - assertFalse(mc.next()); - - h2.setLocation(farAway); - updateAllNodes(); // disconnect, still transferring - - assertTrue(mc.next()); - assertEquals(mc.TYPE_ABORT, mc.getLastType()); - assertEquals(h1, mc.getLastFrom()); - assertFalse(mc.next()); - } - - /** - * try disconnecting on the same update interval when a transfer should - * be finished -> should not cause abort (anymore) - */ + Message m1 = new Message(h1,h2, msgId1, BUFFER_SIZE); + h1.createNewMessage(m1); + checkCreates(1); + + h1.connect(h2); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertFalse(mc.next()); + clock.advance(1); + updateAllNodes(); + assertFalse(mc.next()); + + h2.setLocation(farAway); + updateAllNodes(); // disconnect, still transferring + + assertTrue(mc.next()); + assertEquals(mc.TYPE_ABORT, mc.getLastType()); + assertEquals(h1, mc.getLastFrom()); + assertFalse(mc.next()); + } + + /** + * try disconnecting on the same update interval when a transfer should + * be finished -> should not cause abort (anymore) + */ public void testAbortWhenReady() { - Message m1 = new Message(h2, h1, msgId2, 1); - h2.createNewMessage(m1); - checkCreates(1); - - h2.connect(h1); - updateAllNodes(); // should start transfer - - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - assertFalse(mc.next()); - - clock.advance(10); - h2.setLocation(farAway); - // transfer should have been finished even if nodes disconnected - updateAllNodes(); - - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - assertEquals(h2, mc.getLastFrom()); - assertFalse(mc.next()); - } - - /** - * Test unexpected ordering of finalizations and message transfers. - */ - public void testDifferentOrdering() { + Message m1 = new Message(h2, h1, msgId2, 1); + h2.createNewMessage(m1); + checkCreates(1); + + h2.connect(h1); + updateAllNodes(); // should start transfer + + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertFalse(mc.next()); + + clock.advance(10); + h2.setLocation(farAway); + // transfer should have been finished even if nodes disconnected + updateAllNodes(); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h2, mc.getLastFrom()); + assertFalse(mc.next()); + } + + /** + * Test unexpected ordering of finalizations and message transfers. + */ + public void testDifferentOrdering() { h1.connect(h2); - Message m1 = new Message(h1,h2, msgId1, 1); - h1.createNewMessage(m1); - assertTrue(mc.next()); - assertEquals(mc.TYPE_CREATE, mc.getLastType()); - updateAllNodes(); - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - assertEquals(mc.getLastFrom(),h1); - assertEquals(mc.getLastTo(),h2); - - clock.advance(10); + Message m1 = new Message(h1,h2, msgId1, 1); + h1.createNewMessage(m1); + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(mc.getLastFrom(),h1); + assertEquals(mc.getLastTo(),h2); + + clock.advance(10); // h1 has transferred msg but not finalized transfer when h2 starts - Message m2 = new Message(h2,h1, msgId2, 1); - h2.createNewMessage(m2); - h2.update(true); // h2 and h1 are connected but this shouldn't start relay - - assertTrue(mc.next()); - assertEquals(mc.TYPE_CREATE, mc.getLastType()); - assertFalse(mc.next()); // shouldn't start transfer (prev not finalized) - - h1.update(true); // finalize the transfer of MSG2 - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - assertEquals(h2, mc.getLastTo()); - - // last transfer is finalized -> update should start transfer of msgId2 - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - assertEquals(h1, mc.getLastTo()); - assertEquals(msgId2, mc.getLastMsg().getId()); - - assertFalse(mc.next()); - } - - /** - * Tests if rejecting already delivered message(s) work - */ + Message m2 = new Message(h2,h1, msgId2, 1); + h2.createNewMessage(m2); + h2.update(true); // h2 and h1 are connected but this shouldn't start relay + + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + assertFalse(mc.next()); // shouldn't start transfer (prev not finalized) + + h1.update(true); // finalize the transfer of MSG2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h2, mc.getLastTo()); + + // last transfer is finalized -> update should start transfer of msgId2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(h1, mc.getLastTo()); + assertEquals(msgId2, mc.getLastMsg().getId()); + + assertFalse(mc.next()); + } + + /** + * Tests if rejecting already delivered message(s) work + */ public void testDoubleDelivery() { - Message m1 = new Message(h1,h2, msgId1, 1); - h1.createNewMessage(m1); - - h1.connect(h2); - updateAllNodes(); // starts transfer h1 -> h2 - clock.advance(10); - mc.reset(); // discard create & start - updateAllNodes(); // msg delivered h1 -> h2 - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - assertEquals(h2, mc.getLastTo()); - - h1.connect(h3); - updateAllNodes(); // start transfer h1 -> h3 - assertTrue(mc.next()); - clock.advance(10); - updateAllNodes(); // msg transferred h1 -> h3 - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - assertEquals(h3, mc.getLastTo()); - - h3.connect(h2); - updateAllNodes(); // should not start a new transfer (h1 -> h2) - clock.advance(10); - updateAllNodes(); // still shouldn't do anything - - assertFalse(mc.next()); - } - - /** - * Tests if the FIFO queue management works - */ + Message m1 = new Message(h1,h2, msgId1, 1); + h1.createNewMessage(m1); + + h1.connect(h2); + updateAllNodes(); // starts transfer h1 -> h2 + clock.advance(10); + mc.reset(); // discard create & start + updateAllNodes(); // msg delivered h1 -> h2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h2, mc.getLastTo()); + + h1.connect(h3); + updateAllNodes(); // start transfer h1 -> h3 + assertTrue(mc.next()); + clock.advance(10); + updateAllNodes(); // msg transferred h1 -> h3 + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h3, mc.getLastTo()); + + h3.connect(h2); + updateAllNodes(); // should not start a new transfer (h1 -> h2) + clock.advance(10); + updateAllNodes(); // still shouldn't do anything + + assertFalse(mc.next()); + } + + /** + * Tests if the FIFO queue management works + */ public void testQueueManagement() { - Message m1 = new Message(h1,h3, "dummy", BUFFER_SIZE-1); - h1.createNewMessage(m1); - assertEquals(1, h1.getNrofMessages()); + Message m1 = new Message(h1,h3, "dummy", BUFFER_SIZE-1); + h1.createNewMessage(m1); + assertEquals(1, h1.getNrofMessages()); Message m2 = new Message(h1,h3, msgId1, BUFFER_SIZE/3); - h1.createNewMessage(m2); - assertEquals(1, h1.getNrofMessages()); // message should replace dummy - assertEquals(msgId1, h1.getMessageCollection().iterator().next().getId()); - - mc.reset(); - - clock.advance(10); + h1.createNewMessage(m2); + assertEquals(1, h1.getNrofMessages()); // message should replace dummy + assertEquals(msgId1, h1.getMessageCollection().iterator().next().getId()); + + mc.reset(); + + clock.advance(10); Message m3 = new Message(h1,h3, msgId2, BUFFER_SIZE/3); - h1.createNewMessage(m3); - clock.advance(10); + h1.createNewMessage(m3); + clock.advance(10); Message m4 = new Message(h1,h3, "newestMsg", BUFFER_SIZE/3); - h1.createNewMessage(m4); - - clock.advance(10); + h1.createNewMessage(m4); + + clock.advance(10); Message m5 = new Message(h2,h3, "MSG_from_h2", BUFFER_SIZE/2); - h2.createNewMessage(m5); - - checkCreates(3); // remove 3 creates from mc - - h2.connect(h1); // h2 starts transfer of message -> h1 makes room - h2.update(true); - // h1 should drop first msgId1 and then msgId2 (older first) - assertTrue(mc.next()); - assertEquals(mc.TYPE_DELETE, mc.getLastType()); - assertEquals(h1, mc.getLastFrom()); - assertEquals(msgId1, mc.getLastMsg().getId()); - assertTrue(mc.getLastDropped()); - assertTrue(mc.next()); - assertEquals(mc.TYPE_DELETE, mc.getLastType()); - assertEquals(msgId2, mc.getLastMsg().getId()); - - assertEquals(1, h1.getNrofMessages()); - - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); // h2 should start - assertEquals(h2, mc.getLastFrom()); - assertFalse(mc.next()); - - clock.advance(10); - updateAllNodes(); // h2 should finish transfer - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - assertEquals(h1, mc.getLastTo()); - assertFalse(mc.next()); - } - - /** - * Tests creating a new message when the message buffer is full and the - * message that should be removed is the message being sent - */ - public void testNewMessageToFullBufferWhileTransferring() { - int m3Size = BUFFER_SIZE-1; - int m1Size = BUFFER_SIZE/2; - - Message m1 = new Message(h1,h3, msgId1, m1Size); + h2.createNewMessage(m5); + + checkCreates(3); // remove 3 creates from mc + + h2.connect(h1); // h2 starts transfer of message -> h1 makes room + h2.update(true); + // h1 should drop first msgId1 and then msgId2 (older first) + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(h1, mc.getLastFrom()); + assertEquals(msgId1, mc.getLastMsg().getId()); + assertTrue(mc.getLastDropped()); + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(msgId2, mc.getLastMsg().getId()); + + assertEquals(1, h1.getNrofMessages()); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); // h2 should start + assertEquals(h2, mc.getLastFrom()); + assertFalse(mc.next()); + + clock.advance(10); + updateAllNodes(); // h2 should finish transfer + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h1, mc.getLastTo()); + assertFalse(mc.next()); + } + + /** + * Tests creating a new message when the message buffer is full and the + * message that should be removed is the message being sent + */ + public void testNewMessageToFullBufferWhileTransferring() { + int m3Size = BUFFER_SIZE-1; + int m1Size = BUFFER_SIZE/2; + + Message m1 = new Message(h1,h3, msgId1, m1Size); h1.createNewMessage(m1); - Message m2 = new Message(h1,h4, msgId2, BUFFER_SIZE/2); - h1.createNewMessage(m2); - checkCreates(2); - - h3.connect(h1); - updateAllNodes(); // transfer of msgId1 should start - - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - clock.advance(1); - updateAllNodes(); // should still be transferring - assertFalse(mc.next()); - - // creating a new message should cause dropping the msgId2 but - // not msgId1 (which is being transferred) -> buffer should become + Message m2 = new Message(h1,h4, msgId2, BUFFER_SIZE/2); + h1.createNewMessage(m2); + checkCreates(2); + + h3.connect(h1); + updateAllNodes(); // transfer of msgId1 should start + + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + clock.advance(1); + updateAllNodes(); // should still be transferring + assertFalse(mc.next()); + + // creating a new message should cause dropping the msgId2 but + // not msgId1 (which is being transferred) -> buffer should become // "over full" - Message m3 = new Message(h1,h4, msgId3, m3Size); - h1.createNewMessage(m3); - - assertTrue(mc.next()); - assertEquals(mc.TYPE_DELETE, mc.getLastType()); - assertTrue(mc.getLastDropped()); - assertEquals(msgId2, mc.getLastMsg().getId()); - - assertTrue(mc.next()); - assertEquals(mc.TYPE_CREATE, mc.getLastType()); - assertEquals(msgId3, mc.getLastMsg().getId()); - assertTrue(h1.getBufferOccupancy() > 100); // buffer occupancy > 100% - - assertFalse(mc.next()); - - clock.advance((m1Size/TRANSMIT_SPEED) + 1); - updateAllNodes(); // now transmission should be done - - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - assertEquals(msgId1, mc.getLastMsg().getId()); - - assertTrue(mc.next()); // now should drop the transferred message - assertEquals(mc.TYPE_DELETE, mc.getLastType()); - assertTrue(mc.getLastDropped()); - assertEquals(msgId1, mc.getLastMsg().getId()); - - // buffer occupancy should drop back under 100 % - assertTrue(h1.getBufferOccupancy() < 100); - - // should start transferring msgId3 - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - assertEquals(msgId3, mc.getLastMsg().getId()); - - assertFalse(mc.next()); - } - - public void testTtlExpiry() { + Message m3 = new Message(h1,h4, msgId3, m3Size); + h1.createNewMessage(m3); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertTrue(mc.getLastDropped()); + assertEquals(msgId2, mc.getLastMsg().getId()); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + assertEquals(msgId3, mc.getLastMsg().getId()); + assertTrue(h1.getBufferOccupancy() > 100); // buffer occupancy > 100% + + assertFalse(mc.next()); + + clock.advance((m1Size/TRANSMIT_SPEED) + 1); + updateAllNodes(); // now transmission should be done + + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(msgId1, mc.getLastMsg().getId()); + + assertTrue(mc.next()); // now should drop the transferred message + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertTrue(mc.getLastDropped()); + assertEquals(msgId1, mc.getLastMsg().getId()); + + // buffer occupancy should drop back under 100 % + assertTrue(h1.getBufferOccupancy() < 100); + + // should start transferring msgId3 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(msgId3, mc.getLastMsg().getId()); + + assertFalse(mc.next()); + } + + public void testTtlExpiry() { final int TIME_STEP = 10; - Message m1 = new Message(h1,h3, msgId1, 1); - h1.createNewMessage(m1); - checkCreates(1); - - clock.advance(TIME_STEP); - updateAllNodes(); - assertFalse(mc.next()); - - // relay msg1 from h1 to h2 - h1.connect(h2); - updateAllNodes(); - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - clock.advance(TIME_STEP); - updateAllNodes(); - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - - assertFalse(mc.next()); - - clock.advance((TTL-1)*60 - TIME_STEP*2); - updateAllNodes(); - assertFalse(mc.next()); - Message m2 = new Message(h4,h3, msgId2, 1); - h4.createNewMessage(m2); - checkCreates(1); - - clock.advance(61); - updateAllNodes(); - - // h1 and h2 should delete the expired message - assertTrue(mc.next()); - assertEquals(mc.TYPE_DELETE, mc.getLastType()); - assertEquals(h1, mc.getLastFrom()); - assertEquals(msgId1, mc.getLastMsg().getId()); - - assertTrue(mc.next()); - assertEquals(mc.TYPE_DELETE, mc.getLastType()); - assertEquals(h2, mc.getLastFrom()); - assertEquals(msgId1, mc.getLastMsg().getId()); - - assertFalse(mc.next()); // h4 shouldn't remove the msg just yet - - clock.advance((TTL-1)*60 -61); - updateAllNodes(); - assertFalse(mc.next()); // not yet either - clock.advance(61); - - updateAllNodes(); // but now it's time for h4 to remove the msg - - assertTrue(mc.next()); - assertEquals(mc.TYPE_DELETE, mc.getLastType()); - assertEquals(h4, mc.getLastFrom()); - assertEquals(msgId2, mc.getLastMsg().getId()); - - assertFalse(mc.next()); - } - - public void testResponse() { + Message m1 = new Message(h1,h3, msgId1, 1); + h1.createNewMessage(m1); + checkCreates(1); + + clock.advance(TIME_STEP); + updateAllNodes(); + assertFalse(mc.next()); + + // relay msg1 from h1 to h2 + h1.connect(h2); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + clock.advance(TIME_STEP); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + + assertFalse(mc.next()); + + clock.advance((TTL-1)*60 - TIME_STEP*2); + updateAllNodes(); + assertFalse(mc.next()); + Message m2 = new Message(h4,h3, msgId2, 1); + h4.createNewMessage(m2); + checkCreates(1); + + clock.advance(61); + updateAllNodes(); + + // h1 and h2 should delete the expired message + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(h1, mc.getLastFrom()); + assertEquals(msgId1, mc.getLastMsg().getId()); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(h2, mc.getLastFrom()); + assertEquals(msgId1, mc.getLastMsg().getId()); + + assertFalse(mc.next()); // h4 shouldn't remove the msg just yet + + clock.advance((TTL-1)*60 -61); + updateAllNodes(); + assertFalse(mc.next()); // not yet either + clock.advance(61); + + updateAllNodes(); // but now it's time for h4 to remove the msg + + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(h4, mc.getLastFrom()); + assertEquals(msgId2, mc.getLastMsg().getId()); + + assertFalse(mc.next()); + } + + public void testResponse() { Message m1 = new Message(h1,h3, msgId1, 1); m1.setResponseSize(1); - h1.createNewMessage(m1); - h1.connect(h2); - updateAllNodes(); - clock.advance(10); - updateAllNodes(); - h2.connect(h3); - updateAllNodes(); - - // started h2->h3 relay - mc.reset(); - - clock.advance(10); - updateAllNodes(); - - // finished relay - assertTrue(mc.next()); - assertEquals(mc.TYPE_RELAY, mc.getLastType()); - - // h3 should reply by creating a reply message.. - assertTrue(mc.next()); - assertEquals(mc.TYPE_CREATE, mc.getLastType()); - assertEquals(routing.ActiveRouter.RESPONSE_PREFIX + msgId1, - mc.getLastMsg().getId()); - assertEquals(h3, mc.getLastFrom()); - assertEquals(h1, mc.getLastTo()); - - // .. and starting its transfer - assertTrue(mc.next()); - assertEquals(mc.TYPE_START, mc.getLastType()); - assertEquals(routing.ActiveRouter.RESPONSE_PREFIX + msgId1, - mc.getLastMsg().getId()); - assertEquals(h3, mc.getLastFrom()); - assertEquals(h2, mc.getLastTo()); - - assertFalse(mc.next()); + h1.createNewMessage(m1); + h1.connect(h2); + updateAllNodes(); + clock.advance(10); + updateAllNodes(); + h2.connect(h3); + updateAllNodes(); + + // started h2->h3 relay + mc.reset(); + + clock.advance(10); + updateAllNodes(); + + // finished relay + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + + // h3 should reply by creating a reply message.. + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + assertEquals(routing.ActiveRouter.RESPONSE_PREFIX + msgId1, + mc.getLastMsg().getId()); + assertEquals(h3, mc.getLastFrom()); + assertEquals(h1, mc.getLastTo()); + + // .. and starting its transfer + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(routing.ActiveRouter.RESPONSE_PREFIX + msgId1, + mc.getLastMsg().getId()); + assertEquals(h3, mc.getLastFrom()); + assertEquals(h2, mc.getLastTo()); + + assertFalse(mc.next()); } - + private void newMessage(String id, DTNHost from, DTNHost to) { Message m = new Message(from, to, id, 1); from.createNewMessage(m); @@ -555,7 +555,7 @@ private String runMessageExchange(boolean withDestination) { int nrof = 5; DTNHost dst = h4; DTNHost other = h2; - + clock.setTime(0.0); newMessage("1", h1, dst); clock.advance(2.5); @@ -565,22 +565,22 @@ private String runMessageExchange(boolean withDestination) { clock.advance(1.5); newMessage("3", h1, dst); clock.advance(2.0); - newMessage("4", h1, dst); + newMessage("4", h1, dst); clock.advance(2.5);; - newMessage("5", h1, dst); - + newMessage("5", h1, dst); + if (withDestination) { h1.connect(dst); } else { h1.connect(other); } - + mc.reset(); updateAllNodes(); assertTrue(mc.next()); assertEquals(mc.TYPE_START, mc.getLastType()); - + for (int i=0; i < nrof; i++) { msgIds += mc.getLastMsg().getId()+ " "; clock.advance(10); @@ -592,31 +592,31 @@ private String runMessageExchange(boolean withDestination) { assertEquals(mc.TYPE_START, mc.getLastType()); } } - + assertFalse(mc.next()); return msgIds; } - + public void testFifoSendingQ() throws Exception { - ts.putSetting(MessageRouter.SEND_QUEUE_MODE_S, + ts.putSetting(MessageRouter.SEND_QUEUE_MODE_S, ""+MessageRouter.Q_MODE_FIFO); this.setUp(); String expectedIds = "1 2 3 4 5 "; - + assertEquals(expectedIds, runMessageExchange(true)); assertEquals(expectedIds, runMessageExchange(false)); } - + public void testRandomSendingQ() throws Exception { - ts.putSetting(MessageRouter.SEND_QUEUE_MODE_S, + ts.putSetting(MessageRouter.SEND_QUEUE_MODE_S, ""+MessageRouter.Q_MODE_RANDOM); this.setUp(); - + String orderedIds = "1 2 3 4 5 "; - + assertNotSame(orderedIds, runMessageExchange(true)); assertNotSame(orderedIds, runMessageExchange(false)); - } -} + } +} diff --git a/test/ExternalEventsQueueTest.java b/test/ExternalEventsQueueTest.java index d284e56e8..4bd101365 100644 --- a/test/ExternalEventsQueueTest.java +++ b/test/ExternalEventsQueueTest.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import input.BinaryEventsReader; import input.ExternalEvent; import input.ExternalEventsQueue; @@ -16,85 +16,85 @@ import java.util.List; import junit.framework.TestCase; - -public class ExternalEventsQueueTest extends TestCase { - private final String[] stdinput = { -"1000.000 C MSG_365_D_1 p1 p2 100000", -"1533.405 S MSG_365_D_1 p1 p0", -"1542.000 A MSG_365_D_1 p1 p0", -"2200.000 C MSG_746_D_2 p1 p3 100000", -"3095.408 S MSG_746_D_2 p1 c64", -"3103.000 A MSG_746_D_2 p1 c64", -"8071.608 DE MSG_746_D_2 p1 p10", -" ", // empty line -"8091.608 DE MSG_365_D_1 p1 p10", -"100502.200 DR MSG_365_D_1 p10", -"# comment line", -"106202.613 R MSG_10644_D_5 c70" -}; - - private final double msgTimes[] = {1000.000, 1533.405, 1542.000, - 2200.000, 3095.408, 3103.000, 8071.608, 8091.608, - 100502.200, 106202.613}; - - private ExternalEventsQueue eeq; - private File tempFile; - + +public class ExternalEventsQueueTest extends TestCase { + private final String[] stdinput = { +"1000.000 C MSG_365_D_1 p1 p2 100000", +"1533.405 S MSG_365_D_1 p1 p0", +"1542.000 A MSG_365_D_1 p1 p0", +"2200.000 C MSG_746_D_2 p1 p3 100000", +"3095.408 S MSG_746_D_2 p1 c64", +"3103.000 A MSG_746_D_2 p1 c64", +"8071.608 DE MSG_746_D_2 p1 p10", +" ", // empty line +"8091.608 DE MSG_365_D_1 p1 p10", +"100502.200 DR MSG_365_D_1 p10", +"# comment line", +"106202.613 R MSG_10644_D_5 c70" +}; + + private final double msgTimes[] = {1000.000, 1533.405, 1542.000, + 2200.000, 3095.408, 3103.000, 8071.608, 8091.608, + 100502.200, 106202.613}; + + private ExternalEventsQueue eeq; + private File tempFile; + protected void setUp() throws Exception { - java.util.Locale.setDefault(java.util.Locale.US); - super.setUp(); - String TMP = ".tmp"; - tempFile = File.createTempFile("eeqTest", TMP); - - PrintWriter out = new PrintWriter(tempFile); - - for (String s : stdinput) { - out.println(s); - } - out.close(); - } - - - public void testEEQ() { - int preload = 10; - eeq = new ExternalEventsQueue(tempFile.getAbsolutePath(),preload); - checkEeq(eeq, preload); - - preload = 1; - eeq = new ExternalEventsQueue(tempFile.getAbsolutePath(),preload); - checkEeq(eeq, preload); - } - - - public void testBinaryEEQ() throws Exception{ - int preload = 7; - File tmpBinFile = File.createTempFile("TempBinTest", - BinaryEventsReader.BINARY_EXT); - String binFileName = tmpBinFile.getAbsolutePath(); - ExternalEventsReader r = new StandardEventsReader(tempFile); - List events = r.readEvents(100); - BinaryEventsReader.storeToBinaryFile(binFileName, events); - - eeq = new ExternalEventsQueue(binFileName, preload); - checkEeq(eeq, preload); - - assertTrue(tmpBinFile.delete()); // make sure all locks are gone - } - - - private void checkEeq(ExternalEventsQueue eeq, int preloadVal) { - ExternalEvent ee; - assertEquals(msgTimes[0],eeq.nextEventsTime()); - assertEquals(preloadVal, eeq.eventsLeftInBuffer()); - - ee = eeq.nextEvent(); - assertTrue(ee instanceof MessageCreateEvent); - - for (int i=1; i < msgTimes.length; i++) { - assertEquals(msgTimes[i], eeq.nextEventsTime()); - ee = eeq.nextEvent(); - assertTrue(ee instanceof ExternalEvent); - assertEquals(msgTimes[i], ee.getTime()); - } - } -} + java.util.Locale.setDefault(java.util.Locale.US); + super.setUp(); + String TMP = ".tmp"; + tempFile = File.createTempFile("eeqTest", TMP); + + PrintWriter out = new PrintWriter(tempFile); + + for (String s : stdinput) { + out.println(s); + } + out.close(); + } + + + public void testEEQ() { + int preload = 10; + eeq = new ExternalEventsQueue(tempFile.getAbsolutePath(),preload); + checkEeq(eeq, preload); + + preload = 1; + eeq = new ExternalEventsQueue(tempFile.getAbsolutePath(),preload); + checkEeq(eeq, preload); + } + + + public void testBinaryEEQ() throws Exception{ + int preload = 7; + File tmpBinFile = File.createTempFile("TempBinTest", + BinaryEventsReader.BINARY_EXT); + String binFileName = tmpBinFile.getAbsolutePath(); + ExternalEventsReader r = new StandardEventsReader(tempFile); + List events = r.readEvents(100); + BinaryEventsReader.storeToBinaryFile(binFileName, events); + + eeq = new ExternalEventsQueue(binFileName, preload); + checkEeq(eeq, preload); + + assertTrue(tmpBinFile.delete()); // make sure all locks are gone + } + + + private void checkEeq(ExternalEventsQueue eeq, int preloadVal) { + ExternalEvent ee; + assertEquals(msgTimes[0],eeq.nextEventsTime()); + assertEquals(preloadVal, eeq.eventsLeftInBuffer()); + + ee = eeq.nextEvent(); + assertTrue(ee instanceof MessageCreateEvent); + + for (int i=1; i < msgTimes.length; i++) { + assertEquals(msgTimes[i], eeq.nextEventsTime()); + ee = eeq.nextEvent(); + assertTrue(ee instanceof ExternalEvent); + assertEquals(msgTimes[i], ee.getTime()); + } + } +} diff --git a/test/ExternalMovementReaderTest.java b/test/ExternalMovementReaderTest.java index c53f75d87..c9bf62e71 100644 --- a/test/ExternalMovementReaderTest.java +++ b/test/ExternalMovementReaderTest.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import input.ExternalMovementReader; import java.io.File; @@ -14,64 +14,64 @@ import junit.framework.TestCase; import core.Coord; - -public class ExternalMovementReaderTest extends TestCase { - private ExternalMovementReader r; - private static final String INPUT = - "0 0 0 0 0 0\n"+ - "10 1 10 10\n"+ - "10 2 10 20 1010\n" + - "10 3 10 30\n" + - "20 1 20 10 dummyData\n" + - "20 2 20 20\n" + - "\n"+ - "20 3 30 30\n" + - "30 1 30 20\n" + - "30 2 30 30\n" + - "30 3 40 30"; - private static final String [] ids = {"1","2","3"}; - private static final double [] times = {10,20,30}; - private static final Coord [][] coords = - { {new Coord(10,10), new Coord(10,20), new Coord(10,30)}, - {new Coord(20,10), new Coord(20,20), new Coord(30,30)}, - {new Coord(30,20), new Coord(30,30), new Coord(40,30)} }; - - - protected void setUp() throws Exception { - super.setUp(); - - File tmpFile = File.createTempFile("EMRTest","tmp"); - tmpFile.deleteOnExit(); - - PrintWriter pw = new PrintWriter(tmpFile); - pw.println(INPUT); - pw.close(); - - r = new ExternalMovementReader(tmpFile.getAbsolutePath()); - } - - public void testReader() { - List> list; - - for (int i=0; i> list, String[] ids, - Coord[] coords) { - - assertEquals(ids.length, list.size()); - - for (int i=0; i> list; + + for (int i=0; i> list, String[] ids, + Coord[] coords) { + + assertEquals(ids.length, list.size()); + + for (int i=0; i coords = p.getCoords(); - // should move between n1 and n2 - for (int i=0; i coords = p.getCoords(); + // should move between n1 and n2 + for (int i=0; i coords = p.getCoords(); - // should move between n1 and n2 - for (int i=0; i coords = p.getCoords(); + // should move between n1 and n2 + for (int i=0; i hostsSet; + private List msets; + private Map mapping; + + private MaxPropDijkstra mpd; + private Set targets; + + public void setUp() throws Exception { + super.setUp(); + core.NetworkInterface.reset(); + core.DTNHost.reset(); + TestUtils tu = new TestUtils(null, null, new TestSettings()); + msets = new ArrayList(); + mapping = new HashMap(); + hostsSet = new HashSet(); + + for (int i=0; i(); + } + + /** + * Tests the values that are given as an example in the original paper + */ + public void testProbabilityValuesFromThePaper() { + List nodes = new ArrayList(); + nodes.add(1); + nodes.add(2); + nodes.add(3); + nodes.add(4); + double unknownProb = 1.0/nodes.size(); + + MeetingProbabilitySet mps = new MeetingProbabilitySet(1.0,nodes); + assertEquals(unknownProb, mps.getProbFor(1)); + assertEquals(unknownProb, mps.getProbFor(2)); + + mps.updateMeetingProbFor(1); // h0 meets h1 + + assertEquals(0.625, mps.getProbFor(1)); + assertEquals(0.125, mps.getProbFor(2)); + } + + public void testPath() { + targets.add(1); + targets.add(2); + targets.add(3); + targets.add(4); + targets.add(5); + + MeetingProbabilitySet mps0 = mapping.get(0); + MeetingProbabilitySet mps1 = mapping.get(1); + + mps1.updateMeetingProbFor(2); // h1 meets h2 + assertEquals(1.0, mps1.getProbFor(2)); + + mps1.updateMeetingProbFor(3); // h1 meets h3 + assertEquals(0.5, mps1.getProbFor(2)); + assertEquals(0.5, mps1.getProbFor(3)); + + /* h4 meets h5 and h6 */ + mapping.get(4).updateMeetingProbFor(5); + mapping.get(4).updateMeetingProbFor(6); + + mps1.updateMeetingProbFor(4); // h1 meets h4 + assertEquals(0.25, mps1.getProbFor(2)); + assertEquals(0.25, mps1.getProbFor(3)); + assertEquals(0.5, mps1.getProbFor(4)); + + mps0.updateMeetingProbFor(1); // h0 meets h1 + mps1.updateMeetingProbFor(0); // and vice versa + assertEquals(1.0, mps0.getProbFor(1)); + assertEquals(0.5, mps1.getProbFor(0)); + assertEquals(0.125, mps1.getProbFor(2)); + assertEquals(0.125, mps1.getProbFor(3)); + assertEquals(0.25, mps1.getProbFor(4)); + + mps1.updateMeetingProbFor(4); // h1 meets h4 again + assertEquals(1.0, mps0.getProbFor(1)); // should stay the same + assertEquals(0.25, mps1.getProbFor(0)); + assertEquals(0.0625, mps1.getProbFor(2)); + assertEquals(0.0625, mps1.getProbFor(3)); + assertEquals(0.625, mps1.getProbFor(4)); + + Map result = mpd.getCosts(0, targets); + + assertEquals(0.0, result.get(1)); + assertEquals(1-0.0625, result.get(2)); + assertEquals(1-0.625, result.get(4)); + assertEquals( (1-0.625)+(1-0.5), result.get(5)); + } + + + public void testProbabilitySumsToOne() { + double total; + + mapping.get(0).updateMeetingProbFor(2); + mapping.get(0).updateMeetingProbFor(4); + mapping.get(0).updateMeetingProbFor(2); + + mapping.get(1).updateMeetingProbFor(0); + mapping.get(1).updateMeetingProbFor(0); + + mapping.get(2).updateMeetingProbFor(1); + + mapping.get(3).updateMeetingProbFor(0); + mapping.get(3).updateMeetingProbFor(1); + mapping.get(3).updateMeetingProbFor(2); + mapping.get(3).updateMeetingProbFor(4); + + for (int i=0; i<=3; i++) { + total = 0; + for (int j=0; j cost 1-0.5/2 */ - assertEquals( 1 - 0.5/2 , r1.getCost(h1, h2)); - assertEquals( 1 - (1+0.5)/2 , r1.getCost(h1, h3)); - - disconnect(h1); - h1.connect(h3); - assertEquals( 1 - (0.5/2)/2 , r1.getCost(h1, h2)); - assertEquals( 1 - (1+(1+0.5)/2)/2 , r1.getCost(h1, h3)); - /* probabilities sum to 1.0 */ - assertEquals(1.0, (1-r1.getCost(h1, h2)) + (1-r1.getCost(h1, h3))); - - h1.connect(h4); - assertEquals( 1 - ((0.5/2)/2)/2 , r1.getCost(h1, h2)); - assertEquals( 1 - ((1+(1+0.5)/2)/2)/2 , r1.getCost(h1, h3)); - assertEquals( 1 - 0.5 , r1.getCost(h1, h4)); - assertEquals(1.0, (1-r1.getCost(h1, h2)) + (1-r1.getCost(h1, h3)) + - (1-r1.getCost(h1, h4))); - - disconnect(h1); - h1.connect(h2); // reconnect to h2 - assertEquals( 1 - (1 + ((0.5/2)/2)/2)/2 , r1.getCost(h1, h2)); - assertEquals( 1 - (((1+(1+0.5)/2)/2)/2)/2 , r1.getCost(h1, h3)); - assertEquals( 1 - 0.5/2 , r1.getCost(h1, h4)); - assertEquals(1.0, (1-r1.getCost(h1, h2)) + (1-r1.getCost(h1, h3)) + - (1-r1.getCost(h1, h4))); - - } - - public void testThreshold() { - int msgSize = 90; - - Message m1 = new Message(h1,h5, msgId1, msgSize); - h1.createNewMessage(m1); - checkCreates(1); - h1.connect(h2); - - /* thresholds should be zero before any transfers */ - assertEquals(0, r1.calcThreshold()); - assertEquals(0, r2.calcThreshold()); - - /* simple delivery of msgId1 from h1 to h2 */ - updateAllNodes(); - checkTransferStart(h1, h2, msgId1); - assertFalse(mc.next()); - clock.advance(5); - updateAllNodes(); - assertFalse(mc.next()); // transfer should not be ready yet - clock.advance(5); // now it should be done - updateAllNodes(); - checkDelivered(h1, h2, msgId1, false); - - disconnect(h1); - assertEquals(1, r1.calcThreshold()); - assertEquals(2, r2.calcThreshold()); - - h2.connect(h3); - deliverMessage(h2, h3, msgId1, msgSize, false); - disconnect(h2); - assertEquals(2, r2.calcThreshold()); - /* msg at h3 has traveled 2 hops and "bsize > avgTransferredBytes > 0" - * so threshold should be only msg's hopcount+1 */ - assertEquals(3, r3.calcThreshold()); - } - - public void testAckedMessageDeleting() { - int msgSize = 10; - Message m1 = new Message(h1,h5, msgId1, msgSize); - h1.createNewMessage(m1); - checkCreates(1); - - h1.connect(h2); - deliverMessage(h1, h2, msgId1, msgSize, false); - disconnect(h1); - - h1.connect(h3); - deliverMessage(h1, h3, msgId1, msgSize, false); - disconnect(h1); - - h1.connect(h5); - deliverMessage(h1, h5, msgId1, msgSize, true); - disconnect(h1); - - assertFalse(mc.next()); - h1.connect(h2); // h1 should notify h2 of the delivered msg - assertTrue(mc.next()); - assertEquals(mc.TYPE_DELETE, mc.getLastType()); - assertEquals(msgId1, mc.getLastMsg().getId()); - assertEquals(h2, mc.getLastFrom()); - // the deleted msg truly came from h1? - assertEquals(h1, mc.getLastMsg().getHops().get(0)); - assertFalse(mc.next()); - - // new msg to h3 - Message m2 = new Message(h3,h1, msgId2, msgSize); - h3.createNewMessage(m2); - checkCreates(1); - - h3.connect(h2); // h2 should notify h3 which should delete msgId1 - assertTrue(mc.next()); - assertEquals(mc.TYPE_DELETE, mc.getLastType()); - assertEquals(msgId1, mc.getLastMsg().getId()); - assertEquals(h3, mc.getLastFrom()); - assertFalse(mc.next()); - /* msgId2 should NOT be deleted but it should be transferred to h2 - * during the next update*/ - deliverMessage(h3, h2, msgId2, msgSize, false); - - } - - public void testRouting() { - int msgSize = 10; - DTNHost th1 = utils.createHost(c0, "temp1"); - DTNHost th2 = utils.createHost(c0, "temp2"); - DTNHost th3 = utils.createHost(c0, "temp3"); - DTNHost th4 = utils.createHost(c0, "temp4"); - - h4.connect(th1); - h4.connect(h5); - disconnect(h4); - h4.connect(th1); - disconnect(h4); - /* h4 should have probs: h5:0.25, th1:0.75 */ - - h3.connect(th2); - h3.connect(h4); - disconnect(h3); - /* h3 probs: h4:0.5, th2:0.5 - * h4 probs: h3:0.5, th1:0.375, h5:0.125 */ - - h2.connect(th3); - disconnect(h2); - h2.connect(h3); - h2.connect(th3); - disconnect(h2); - h2.connect(th3); - disconnect(h2); - /* h2 probs: th3:0.875, h3:0.125 - * h3 probs: h2:0.5, h4:0.25, th2:0.25 */ - - h1.connect(th4); - h1.connect(h2); - disconnect(h1); - /* h1 probs: th4:0.5, h2:0.5 - * h2 probs: h1:0.5, th3:0.4375, h3:0.0625*/ - - h4.connect(h5); - disconnect(h4); - /* h4 probs: h3:0.25, th1:0.1875, h5:0.5625 - * these changes should not be visible to h3! */ - Message m1 = new Message(h1,h5, msgId1, msgSize); - h1.createNewMessage(m1); - - /* msg with path h1 -> h2 -> h3 -> h4 -> h5 */ - double trueCost = (1-0.5) + (1-0.0625) + (1-0.25) + (1-0.125); - double calcCost = r1.getCost(h1, h5); - assertEquals(trueCost, calcCost); - } - - /** - * Tests that more recent meeting probability sets replace older ones - * but not vice versa. - */ - public void testMpsTimeStamps() { - /* create some messages so we can ask costs to destinations */ - int msgIndx = 1; - Message m1 = new Message(h1,h2, ""+msgIndx++, 1); - h1.createNewMessage(m1); - Message m2 = new Message(h1,h1, ""+msgIndx++, 1); - h1.createNewMessage(m2); - Message m3 = new Message(h1,h3, ""+msgIndx++, 1); - h1.createNewMessage(m3); - Message m4 = new Message(h3,h2, ""+msgIndx++, 1); - h3.createNewMessage(m4); - Message m5 = new Message(h3,h3, ""+msgIndx++, 1); - h3.createNewMessage(m5); - Message m6 = new Message(h4,h3, ""+msgIndx++, 1); - h4.createNewMessage(m6); - Message m7 = new Message(h4,h4, ""+msgIndx++, 1); - h4.createNewMessage(m7); - Message m8 = new Message(h2,h2, ""+msgIndx++, 1); - h2.createNewMessage(m8); - Message m9 = new Message(h2,h4, ""+msgIndx++, 1); - h2.createNewMessage(m9); - - h1.connect(h2); - disconnect(h1); - /* now we should have - * h1': h2:1.0; h2:h2' - * h2': h1:1.0; h1:h1' */ - - assertEquals(0.0, r1.getCost(h1, h2)); - assertEquals(0.0, r1.getCost(h2, h1)); - - clock.advance(1.0); - h1.connect(h3); - disconnect(h1); - /* h1'': h2:0.5, h3:0.5; h2:h2', h3:h3' - * h3': h1:1.0; h1:h1'', h2:h2' */ - - assertEquals(0.5, r1.getCost(h1, h2)); - /* h3 received h1's other probs properly? */ - assertEquals(0.5, r3.getCost(h1, h2)); - assertEquals(0.5, r3.getCost(h1, h3)); - - clock.advance(1.0); - h1.connect(h4); - disconnect(h1); - /* h1''': h2:0.25, h3:0.25, h4:0.5; h2:h2', h3:h3', h4:h4' - * h4': h1:1.0; h1:h1''', h2:h2', h3:h3'*/ - - assertEquals(0.75, r4.getCost(h1, h3)); - assertEquals(0.5, r4.getCost(h1, h4)); - - clock.advance(1.0); - h2.connect(h3); - disconnect(h2); - /* h2'': h1:0.5, h3:0.5; h1:h1'', h3:h3'' (both from h3) - * h3'': h1:0.5, h2:0.5; h1:h1'', h2:h2'' (h1's probs should remain) */ - - assertEquals(0.5, r2.getCost(h1, h2)); // test the received h1'' - assertEquals(0.5, r3.getCost(h1, h2)); // is h1'' also still in h3? - - clock.advance(1.0); - h1.connect(h2); - disconnect(h1); - /* h1'''': h2:0.625, h3:0.125, h4:0.25; h2:h2''', h3:h3'', h4:h4' - * h2''': h1:0.75, h3:0.25; h1:h1'''', h2:h3'', h4:h4' */ - - /* msg path h2->h1->h4 */ - assertEquals((1-0.75)+(1-0.25), r2.getCost(h2, h4)); - } -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import routing.MaxPropRouter; +import routing.MessageRouter; +import core.DTNHost; +import core.Message; +import core.SimScenario; + +/** + * Tests for the MaxProp routing module + */ +public class MaxPropRouterTest extends AbstractRouterTest { + + private MaxPropRouter r1,r2,r3,r4; + private static final int NROF_HOSTS = 10; + private static final double INVALID_COST = Double.MAX_VALUE; + + protected void setUp() throws Exception { + ts.putSetting(MessageRouter.B_SIZE_S, ""+BUFFER_SIZE); + ts.putSetting(SimScenario.SCENARIO_NS + "." + + SimScenario.NROF_GROUPS_S, "1"); + ts.putSetting(SimScenario.GROUP_NS + "." + + core.SimScenario.NROF_HOSTS_S, "" + NROF_HOSTS); + setRouterProto(new MaxPropRouter(ts)); + super.setUp(); + + r1 = (MaxPropRouter)h1.getRouter(); + r2 = (MaxPropRouter)h2.getRouter(); + r3 = (MaxPropRouter)h3.getRouter(); + r4 = (MaxPropRouter)h4.getRouter(); + } + + public void testCostValues() { + /* create messages so we can ask for msg costs */ + + Message m1 = new Message(h1,h2, msgId2, 10); + h1.createNewMessage(m1); + Message m2 = new Message(h1,h3, msgId3, 10); + h1.createNewMessage(m2); + Message m3 = new Message(h1,h4, msgId4, 10); + h1.createNewMessage(m3); + + Message m4 = new Message(h2,h1, msgId5, 10); + h2.createNewMessage(m4); + checkCreates(4); + + /* there should be no routes before connects */ + assertEquals(INVALID_COST, r1.getCost(h1, h2)); + assertEquals(INVALID_COST, r2.getCost(h2, h1)); + + h1.connect(h2); + assertEquals(0.0, r1.getCost(h1, h2)); // zero cost route to only known + assertEquals(0.0, r2.getCost(h2, h1)); + + disconnect(h1); // disconnect should not affect the costs + assertEquals(0.0, r1.getCost(h1, h2)); + assertEquals(0.0, r2.getCost(h2, h1)); + + h1.connect(h2); // costs should stay the same (only 1 known host) + assertEquals(0.0, r1.getCost(h1, h2)); + assertEquals(0.0, r2.getCost(h2, h1)); + + disconnect(h1); + h1.connect(h3); + assertEquals(0.5, r1.getCost(h1, h2)); + assertEquals(0.5, r1.getCost(h1, h3)); + assertEquals(0.0, r2.getCost(h2, h1)); // h2's costs should not change + + disconnect(h1); + h1.connect(h3); + /* h1's prob of meeting h2 is 0.5/2 -> cost 1-0.5/2 */ + assertEquals( 1 - 0.5/2 , r1.getCost(h1, h2)); + assertEquals( 1 - (1+0.5)/2 , r1.getCost(h1, h3)); + + disconnect(h1); + h1.connect(h3); + assertEquals( 1 - (0.5/2)/2 , r1.getCost(h1, h2)); + assertEquals( 1 - (1+(1+0.5)/2)/2 , r1.getCost(h1, h3)); + /* probabilities sum to 1.0 */ + assertEquals(1.0, (1-r1.getCost(h1, h2)) + (1-r1.getCost(h1, h3))); + + h1.connect(h4); + assertEquals( 1 - ((0.5/2)/2)/2 , r1.getCost(h1, h2)); + assertEquals( 1 - ((1+(1+0.5)/2)/2)/2 , r1.getCost(h1, h3)); + assertEquals( 1 - 0.5 , r1.getCost(h1, h4)); + assertEquals(1.0, (1-r1.getCost(h1, h2)) + (1-r1.getCost(h1, h3)) + + (1-r1.getCost(h1, h4))); + + disconnect(h1); + h1.connect(h2); // reconnect to h2 + assertEquals( 1 - (1 + ((0.5/2)/2)/2)/2 , r1.getCost(h1, h2)); + assertEquals( 1 - (((1+(1+0.5)/2)/2)/2)/2 , r1.getCost(h1, h3)); + assertEquals( 1 - 0.5/2 , r1.getCost(h1, h4)); + assertEquals(1.0, (1-r1.getCost(h1, h2)) + (1-r1.getCost(h1, h3)) + + (1-r1.getCost(h1, h4))); + + } + + public void testThreshold() { + int msgSize = 90; + + Message m1 = new Message(h1,h5, msgId1, msgSize); + h1.createNewMessage(m1); + checkCreates(1); + h1.connect(h2); + + /* thresholds should be zero before any transfers */ + assertEquals(0, r1.calcThreshold()); + assertEquals(0, r2.calcThreshold()); + + /* simple delivery of msgId1 from h1 to h2 */ + updateAllNodes(); + checkTransferStart(h1, h2, msgId1); + assertFalse(mc.next()); + clock.advance(5); + updateAllNodes(); + assertFalse(mc.next()); // transfer should not be ready yet + clock.advance(5); // now it should be done + updateAllNodes(); + checkDelivered(h1, h2, msgId1, false); + + disconnect(h1); + assertEquals(1, r1.calcThreshold()); + assertEquals(2, r2.calcThreshold()); + + h2.connect(h3); + deliverMessage(h2, h3, msgId1, msgSize, false); + disconnect(h2); + assertEquals(2, r2.calcThreshold()); + /* msg at h3 has traveled 2 hops and "bsize > avgTransferredBytes > 0" + * so threshold should be only msg's hopcount+1 */ + assertEquals(3, r3.calcThreshold()); + } + + public void testAckedMessageDeleting() { + int msgSize = 10; + Message m1 = new Message(h1,h5, msgId1, msgSize); + h1.createNewMessage(m1); + checkCreates(1); + + h1.connect(h2); + deliverMessage(h1, h2, msgId1, msgSize, false); + disconnect(h1); + + h1.connect(h3); + deliverMessage(h1, h3, msgId1, msgSize, false); + disconnect(h1); + + h1.connect(h5); + deliverMessage(h1, h5, msgId1, msgSize, true); + disconnect(h1); + + assertFalse(mc.next()); + h1.connect(h2); // h1 should notify h2 of the delivered msg + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(msgId1, mc.getLastMsg().getId()); + assertEquals(h2, mc.getLastFrom()); + // the deleted msg truly came from h1? + assertEquals(h1, mc.getLastMsg().getHops().get(0)); + assertFalse(mc.next()); + + // new msg to h3 + Message m2 = new Message(h3,h1, msgId2, msgSize); + h3.createNewMessage(m2); + checkCreates(1); + + h3.connect(h2); // h2 should notify h3 which should delete msgId1 + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(msgId1, mc.getLastMsg().getId()); + assertEquals(h3, mc.getLastFrom()); + assertFalse(mc.next()); + /* msgId2 should NOT be deleted but it should be transferred to h2 + * during the next update*/ + deliverMessage(h3, h2, msgId2, msgSize, false); + + } + + public void testRouting() { + int msgSize = 10; + DTNHost th1 = utils.createHost(c0, "temp1"); + DTNHost th2 = utils.createHost(c0, "temp2"); + DTNHost th3 = utils.createHost(c0, "temp3"); + DTNHost th4 = utils.createHost(c0, "temp4"); + + h4.connect(th1); + h4.connect(h5); + disconnect(h4); + h4.connect(th1); + disconnect(h4); + /* h4 should have probs: h5:0.25, th1:0.75 */ + + h3.connect(th2); + h3.connect(h4); + disconnect(h3); + /* h3 probs: h4:0.5, th2:0.5 + * h4 probs: h3:0.5, th1:0.375, h5:0.125 */ + + h2.connect(th3); + disconnect(h2); + h2.connect(h3); + h2.connect(th3); + disconnect(h2); + h2.connect(th3); + disconnect(h2); + /* h2 probs: th3:0.875, h3:0.125 + * h3 probs: h2:0.5, h4:0.25, th2:0.25 */ + + h1.connect(th4); + h1.connect(h2); + disconnect(h1); + /* h1 probs: th4:0.5, h2:0.5 + * h2 probs: h1:0.5, th3:0.4375, h3:0.0625*/ + + h4.connect(h5); + disconnect(h4); + /* h4 probs: h3:0.25, th1:0.1875, h5:0.5625 + * these changes should not be visible to h3! */ + Message m1 = new Message(h1,h5, msgId1, msgSize); + h1.createNewMessage(m1); + + /* msg with path h1 -> h2 -> h3 -> h4 -> h5 */ + double trueCost = (1-0.5) + (1-0.0625) + (1-0.25) + (1-0.125); + double calcCost = r1.getCost(h1, h5); + assertEquals(trueCost, calcCost); + } + + /** + * Tests that more recent meeting probability sets replace older ones + * but not vice versa. + */ + public void testMpsTimeStamps() { + /* create some messages so we can ask costs to destinations */ + int msgIndx = 1; + Message m1 = new Message(h1,h2, ""+msgIndx++, 1); + h1.createNewMessage(m1); + Message m2 = new Message(h1,h1, ""+msgIndx++, 1); + h1.createNewMessage(m2); + Message m3 = new Message(h1,h3, ""+msgIndx++, 1); + h1.createNewMessage(m3); + Message m4 = new Message(h3,h2, ""+msgIndx++, 1); + h3.createNewMessage(m4); + Message m5 = new Message(h3,h3, ""+msgIndx++, 1); + h3.createNewMessage(m5); + Message m6 = new Message(h4,h3, ""+msgIndx++, 1); + h4.createNewMessage(m6); + Message m7 = new Message(h4,h4, ""+msgIndx++, 1); + h4.createNewMessage(m7); + Message m8 = new Message(h2,h2, ""+msgIndx++, 1); + h2.createNewMessage(m8); + Message m9 = new Message(h2,h4, ""+msgIndx++, 1); + h2.createNewMessage(m9); + + h1.connect(h2); + disconnect(h1); + /* now we should have + * h1': h2:1.0; h2:h2' + * h2': h1:1.0; h1:h1' */ + + assertEquals(0.0, r1.getCost(h1, h2)); + assertEquals(0.0, r1.getCost(h2, h1)); + + clock.advance(1.0); + h1.connect(h3); + disconnect(h1); + /* h1'': h2:0.5, h3:0.5; h2:h2', h3:h3' + * h3': h1:1.0; h1:h1'', h2:h2' */ + + assertEquals(0.5, r1.getCost(h1, h2)); + /* h3 received h1's other probs properly? */ + assertEquals(0.5, r3.getCost(h1, h2)); + assertEquals(0.5, r3.getCost(h1, h3)); + + clock.advance(1.0); + h1.connect(h4); + disconnect(h1); + /* h1''': h2:0.25, h3:0.25, h4:0.5; h2:h2', h3:h3', h4:h4' + * h4': h1:1.0; h1:h1''', h2:h2', h3:h3'*/ + + assertEquals(0.75, r4.getCost(h1, h3)); + assertEquals(0.5, r4.getCost(h1, h4)); + + clock.advance(1.0); + h2.connect(h3); + disconnect(h2); + /* h2'': h1:0.5, h3:0.5; h1:h1'', h3:h3'' (both from h3) + * h3'': h1:0.5, h2:0.5; h1:h1'', h2:h2'' (h1's probs should remain) */ + + assertEquals(0.5, r2.getCost(h1, h2)); // test the received h1'' + assertEquals(0.5, r3.getCost(h1, h2)); // is h1'' also still in h3? + + clock.advance(1.0); + h1.connect(h2); + disconnect(h1); + /* h1'''': h2:0.625, h3:0.125, h4:0.25; h2:h2''', h3:h3'', h4:h4' + * h2''': h1:0.75, h3:0.25; h1:h1'''', h2:h3'', h4:h4' */ + + /* msg path h2->h1->h4 */ + assertEquals((1-0.75)+(1-0.25), r2.getCost(h2, h4)); + } +} diff --git a/test/MessageChecker.java b/test/MessageChecker.java index 42616bec8..3336aeb47 100644 --- a/test/MessageChecker.java +++ b/test/MessageChecker.java @@ -1,159 +1,159 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import java.util.ArrayList; import core.DTNHost; import core.Message; import core.MessageListener; - -/** - * Message event checker for tests. - */ -public class MessageChecker implements MessageListener { - private Message lastMsg; - private DTNHost lastFrom; - private DTNHost lastTo; - private Boolean lastDropped; - private Boolean lastFirstDelivery; - private String lastType; - private ArrayList queue; - - public final String TYPE_NONE = "none"; - public final String TYPE_DELETE = "delete"; - public final String TYPE_ABORT = "abort"; - public final String TYPE_RELAY = "relay"; - public final String TYPE_CREATE = "create"; - public final String TYPE_START = "start"; - - public MessageChecker() { - reset(); - } - - public void reset() { - this.queue = new ArrayList(); - this.lastType = TYPE_NONE; - this.lastMsg = null; - this.lastFrom = null; - this.lastTo = null; - this.lastDropped = null; - this.lastFirstDelivery = null; - } - - public void messageDeleted(Message m, DTNHost where, boolean dropped) { - this.add(m, where, null, TYPE_DELETE, dropped, null); - } - - public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { - this.add(m, from, to, TYPE_ABORT, null, null); - } - - public void messageTransferred(Message m, DTNHost from, DTNHost to, - boolean firstDelivery) { - this.add(m, from, to, TYPE_RELAY, null, firstDelivery); - } - - public void newMessage(Message m) { - this.add(m, m.getFrom(), m.getTo(), TYPE_CREATE, null, null); - } - - - public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { - this.add(m, from, to, TYPE_START, null, null); - } - - public boolean next() { - if (this.queue.size() == 0) { - return false; - } - - MsgCheckerEvent e = this.queue.remove(0); - - this.lastMsg = e.msg; - this.lastFrom = e.from; - this.lastTo = e.to; - this.lastType = e.type; - this.lastFirstDelivery = e.delivered; - this.lastDropped = e.dropped; - return true; - - } - - private void add(Message m, DTNHost from, DTNHost to, String type, Boolean - dropped, Boolean delivered) { - this.queue.add(new MsgCheckerEvent(m,from,to,type,dropped,delivered)); - } - - /** - * @return the lastFirstDelivery - */ - public Boolean getLastFirstDelivery() { - return lastFirstDelivery; - } - - /** - * @return the lastDropped - */ - public Boolean getLastDropped() { - return lastDropped; - } - - /** - * @return the lastFrom - */ - public DTNHost getLastFrom() { - return lastFrom; - } - - /** - * @return the lastMsg - */ - public Message getLastMsg() { - return lastMsg; - } - - /** - * @return the lastTo - */ - public DTNHost getLastTo() { - return lastTo; - } - - /** - * @return the lastType - */ - public String getLastType() { - return lastType; - } - - public String toString() { - return this.queue.size() + " event(s) : " + this.queue; - } - - private class MsgCheckerEvent { - private Message msg; - private DTNHost from; - private DTNHost to; - private Boolean dropped; - private Boolean delivered; - private String type; - - public MsgCheckerEvent(Message m, DTNHost from, DTNHost to, - String type, Boolean dropped, Boolean delivered) { - this.msg = m; - this.from = from; - this.to = to; - this.type = type; - this.dropped = dropped; - this.delivered = delivered; - } - - public String toString() { - return this.type + " (" + this.from + "->" + this.to+") " + - this.msg; - } - } -} + +/** + * Message event checker for tests. + */ +public class MessageChecker implements MessageListener { + private Message lastMsg; + private DTNHost lastFrom; + private DTNHost lastTo; + private Boolean lastDropped; + private Boolean lastFirstDelivery; + private String lastType; + private ArrayList queue; + + public final String TYPE_NONE = "none"; + public final String TYPE_DELETE = "delete"; + public final String TYPE_ABORT = "abort"; + public final String TYPE_RELAY = "relay"; + public final String TYPE_CREATE = "create"; + public final String TYPE_START = "start"; + + public MessageChecker() { + reset(); + } + + public void reset() { + this.queue = new ArrayList(); + this.lastType = TYPE_NONE; + this.lastMsg = null; + this.lastFrom = null; + this.lastTo = null; + this.lastDropped = null; + this.lastFirstDelivery = null; + } + + public void messageDeleted(Message m, DTNHost where, boolean dropped) { + this.add(m, where, null, TYPE_DELETE, dropped, null); + } + + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { + this.add(m, from, to, TYPE_ABORT, null, null); + } + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + this.add(m, from, to, TYPE_RELAY, null, firstDelivery); + } + + public void newMessage(Message m) { + this.add(m, m.getFrom(), m.getTo(), TYPE_CREATE, null, null); + } + + + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { + this.add(m, from, to, TYPE_START, null, null); + } + + public boolean next() { + if (this.queue.size() == 0) { + return false; + } + + MsgCheckerEvent e = this.queue.remove(0); + + this.lastMsg = e.msg; + this.lastFrom = e.from; + this.lastTo = e.to; + this.lastType = e.type; + this.lastFirstDelivery = e.delivered; + this.lastDropped = e.dropped; + return true; + + } + + private void add(Message m, DTNHost from, DTNHost to, String type, Boolean + dropped, Boolean delivered) { + this.queue.add(new MsgCheckerEvent(m,from,to,type,dropped,delivered)); + } + + /** + * @return the lastFirstDelivery + */ + public Boolean getLastFirstDelivery() { + return lastFirstDelivery; + } + + /** + * @return the lastDropped + */ + public Boolean getLastDropped() { + return lastDropped; + } + + /** + * @return the lastFrom + */ + public DTNHost getLastFrom() { + return lastFrom; + } + + /** + * @return the lastMsg + */ + public Message getLastMsg() { + return lastMsg; + } + + /** + * @return the lastTo + */ + public DTNHost getLastTo() { + return lastTo; + } + + /** + * @return the lastType + */ + public String getLastType() { + return lastType; + } + + public String toString() { + return this.queue.size() + " event(s) : " + this.queue; + } + + private class MsgCheckerEvent { + private Message msg; + private DTNHost from; + private DTNHost to; + private Boolean dropped; + private Boolean delivered; + private String type; + + public MsgCheckerEvent(Message m, DTNHost from, DTNHost to, + String type, Boolean dropped, Boolean delivered) { + this.msg = m; + this.from = from; + this.to = to; + this.type = type; + this.dropped = dropped; + this.delivered = delivered; + } + + public String toString() { + return this.type + " (" + this.from + "->" + this.to+") " + + this.msg; + } + } +} diff --git a/test/MessageGraphvizReportTest.java b/test/MessageGraphvizReportTest.java index 530c112d7..97f58e972 100644 --- a/test/MessageGraphvizReportTest.java +++ b/test/MessageGraphvizReportTest.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -16,62 +16,62 @@ import core.DTNHost; import core.Message; import core.MessageListener; - -public class MessageGraphvizReportTest extends TestCase { - private File outFile; - private MessageGraphvizReport r; - private TestUtils utils; - - public void setUp() throws IOException { - TestSettings ts = new TestSettings(); - outFile = File.createTempFile("mgtest", ".tmp"); - outFile.deleteOnExit(); - - ts.putSetting("MessageGraphvizReport.output", outFile.getAbsolutePath()); - ts.putSetting("MessageGraphvizReport.interval" , ""); - - Vector ml = new Vector(); - r = new MessageGraphvizReport(); - ml.add(r); - utils = new TestUtils(null, ml, ts); - } - - private void generateMessages() { - Coord c1 = new Coord(0,0); - Coord c2 = new Coord(1,0); - Coord c3 = new Coord(2,0); - - utils.setTransmitRange(2); - DTNHost h1 = utils.createHost(c1,"h1"); - DTNHost h2 = utils.createHost(c2,"h2"); - DTNHost h3 = utils.createHost(c3,"h3"); - - h1.createNewMessage(new Message(h1, h3, "M1", 1)); - h1.sendMessage("M1", h2); - h2.messageTransferred("M1", h1); - h2.sendMessage("M1", h3); - h3.messageTransferred("M1", h2); - h3.createNewMessage(new Message(h3, h2, "M2", 1)); - h3.sendMessage("M2", h2); - h2.messageTransferred("M2", h3); - } - - public void testDone() throws IOException{ - BufferedReader reader; - - generateMessages(); - r.done(); - - reader = new BufferedReader(new FileReader(outFile)); - reader.readLine(); // read comment lines - reader.readLine(); // read comment lines - assertEquals("digraph " + MessageGraphvizReport.GRAPH_NAME + - " {", reader.readLine()); - assertEquals("\th1->h2->h3;",reader.readLine()); - assertEquals("\th3->h2;",reader.readLine()); + +public class MessageGraphvizReportTest extends TestCase { + private File outFile; + private MessageGraphvizReport r; + private TestUtils utils; + + public void setUp() throws IOException { + TestSettings ts = new TestSettings(); + outFile = File.createTempFile("mgtest", ".tmp"); + outFile.deleteOnExit(); + + ts.putSetting("MessageGraphvizReport.output", outFile.getAbsolutePath()); + ts.putSetting("MessageGraphvizReport.interval" , ""); + + Vector ml = new Vector(); + r = new MessageGraphvizReport(); + ml.add(r); + utils = new TestUtils(null, ml, ts); + } + + private void generateMessages() { + Coord c1 = new Coord(0,0); + Coord c2 = new Coord(1,0); + Coord c3 = new Coord(2,0); + + utils.setTransmitRange(2); + DTNHost h1 = utils.createHost(c1,"h1"); + DTNHost h2 = utils.createHost(c2,"h2"); + DTNHost h3 = utils.createHost(c3,"h3"); + + h1.createNewMessage(new Message(h1, h3, "M1", 1)); + h1.sendMessage("M1", h2); + h2.messageTransferred("M1", h1); + h2.sendMessage("M1", h3); + h3.messageTransferred("M1", h2); + h3.createNewMessage(new Message(h3, h2, "M2", 1)); + h3.sendMessage("M2", h2); + h2.messageTransferred("M2", h3); + } + + public void testDone() throws IOException{ + BufferedReader reader; + + generateMessages(); + r.done(); + + reader = new BufferedReader(new FileReader(outFile)); + reader.readLine(); // read comment lines + reader.readLine(); // read comment lines + assertEquals("digraph " + MessageGraphvizReport.GRAPH_NAME + + " {", reader.readLine()); + assertEquals("\th1->h2->h3;",reader.readLine()); + assertEquals("\th3->h2;",reader.readLine()); assertEquals("}",reader.readLine()); - - reader.close(); - } - -} + + reader.close(); + } + +} diff --git a/test/MessageTest.java b/test/MessageTest.java index 0ca1b592d..49be33e14 100644 --- a/test/MessageTest.java +++ b/test/MessageTest.java @@ -1,64 +1,64 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package test; - -import junit.framework.TestCase; - -import org.junit.Before; -import org.junit.Test; - -import core.DTNHost; -import core.Message; -import core.SimClock; - -public class MessageTest extends TestCase { - - private Message msg; - private DTNHost from; - private DTNHost to; - private SimClock sc; - - @Before - public void setUp() throws Exception { - sc = SimClock.getInstance(); - sc.setTime(10); - - msg = new Message(from, to, "M", 100); - msg.setTtl(10); - - } - - @Test - public void testGetTtl() { - assertEquals(10, msg.getTtl()); - - sc.advance(50); - assertEquals(9, msg.getTtl()); - - sc.advance(120); - assertEquals(7, msg.getTtl()); - - sc.advance(180); - assertEquals(4, msg.getTtl()); - - sc.advance(240); - assertEquals(0, msg.getTtl()); - - - } - - @Test - public void testAddProperty() { - String value1 = "value1"; - String value2 = "value2"; - msg.addProperty("foo", value1); - msg.addProperty("bar", value2); - - assertEquals(value1, msg.getProperty("foo")); - assertEquals(value2, msg.getProperty("bar")); - } - - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import junit.framework.TestCase; + +import org.junit.Before; +import org.junit.Test; + +import core.DTNHost; +import core.Message; +import core.SimClock; + +public class MessageTest extends TestCase { + + private Message msg; + private DTNHost from; + private DTNHost to; + private SimClock sc; + + @Before + public void setUp() throws Exception { + sc = SimClock.getInstance(); + sc.setTime(10); + + msg = new Message(from, to, "M", 100); + msg.setTtl(10); + + } + + @Test + public void testGetTtl() { + assertEquals(10, msg.getTtl()); + + sc.advance(50); + assertEquals(9, msg.getTtl()); + + sc.advance(120); + assertEquals(7, msg.getTtl()); + + sc.advance(180); + assertEquals(4, msg.getTtl()); + + sc.advance(240); + assertEquals(0, msg.getTtl()); + + + } + + @Test + public void testAddProperty() { + String value1 = "value1"; + String value2 = "value2"; + msg.addProperty("foo", value1); + msg.addProperty("bar", value2); + + assertEquals(value1, msg.getProperty("foo")); + assertEquals(value2, msg.getProperty("bar")); + } + + +} diff --git a/test/ModuleCommunicationBusTest.java b/test/ModuleCommunicationBusTest.java index 02fe6a3f3..5909f36fa 100644 --- a/test/ModuleCommunicationBusTest.java +++ b/test/ModuleCommunicationBusTest.java @@ -1,106 +1,106 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package test; - -import junit.framework.TestCase; - -import org.junit.Before; -import org.junit.Test; - -import core.ModuleCommunicationBus; -import core.ModuleCommunicationListener; - -public class ModuleCommunicationBusTest extends TestCase { - - private ModuleCommunicationBus b; - private static final String TST_VAL = "test-value"; - private String notifyKey; - private Object notifyValue; - private ModuleCommunicationListener mcl; - - @Before - public void setUp() throws Exception { - b = new ModuleCommunicationBus(); - this.notifyKey = null; - this.notifyValue = null; - - this.mcl = new ModuleCommunicationListener() { - public void moduleValueChanged(String key, Object newValue) { - notifyKey = key; - notifyValue = newValue; - } - }; - - } - - @Test - public void testGetProperty() { - assertNull(b.getProperty("test")); - b.addProperty("test", TST_VAL); - assertEquals(TST_VAL, b.getProperty("test").toString()); - assertNull(b.getProperty("invalidValue")); - - b.addProperty("test2", "value2"); - assertEquals("value2", b.getProperty("test2".toString())); - assertEquals(TST_VAL, b.getProperty("test").toString()); - } - - @Test - public void testUpdateProperty() { - b.addProperty("test", TST_VAL); - assertEquals(TST_VAL, b.getProperty("test").toString()); - b.updateProperty("test", "new value"); - assertEquals("new value", b.getProperty("test").toString()); - } - - @Test - public void testSubscribe() { - String key = "subtst"; - - b.addProperty(key, "test"); - b.subscribe(key, mcl); - assertNull(notifyKey); - assertNull(notifyValue); - - b.updateProperty(key, "test2"); - assertEquals(key, notifyKey); - assertEquals("test2", notifyValue.toString()); - - b.updateProperty(key, "newTest"); - assertEquals(key, notifyKey); - assertEquals("newTest", notifyValue.toString()); - } - - @Test - public void testUnsubscribe() { - String key = "unsubtst"; - String tstVal = "unsubtstvalue"; - b.subscribe(key, mcl); - b.updateProperty(key, tstVal); - b.unsubscribe(key, mcl); - - b.updateProperty(key, "newvalue"); - assertEquals("newvalue", b.getProperty(key).toString()); - assertEquals(key, notifyKey); - assertEquals(tstVal, notifyValue.toString()); - } - - @Test - public void testUpdateDouble() { - String key = "doubletst"; - Double val = 15.5; - - b.addProperty(key, val); - assertEquals(16.5, b.updateDouble(key, 1.0)); - assertEquals(16.5, b.getDouble(key, -1.0)); - - assertEquals(13.3, b.updateDouble(key, -3.2)); - assertEquals(13.3, b.getDouble(key, -1.0)); - - assertEquals(-16.7, b.updateDouble(key, -30)); - assertEquals(-16.7, b.getDouble(key, -1.0)); - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import junit.framework.TestCase; + +import org.junit.Before; +import org.junit.Test; + +import core.ModuleCommunicationBus; +import core.ModuleCommunicationListener; + +public class ModuleCommunicationBusTest extends TestCase { + + private ModuleCommunicationBus b; + private static final String TST_VAL = "test-value"; + private String notifyKey; + private Object notifyValue; + private ModuleCommunicationListener mcl; + + @Before + public void setUp() throws Exception { + b = new ModuleCommunicationBus(); + this.notifyKey = null; + this.notifyValue = null; + + this.mcl = new ModuleCommunicationListener() { + public void moduleValueChanged(String key, Object newValue) { + notifyKey = key; + notifyValue = newValue; + } + }; + + } + + @Test + public void testGetProperty() { + assertNull(b.getProperty("test")); + b.addProperty("test", TST_VAL); + assertEquals(TST_VAL, b.getProperty("test").toString()); + assertNull(b.getProperty("invalidValue")); + + b.addProperty("test2", "value2"); + assertEquals("value2", b.getProperty("test2".toString())); + assertEquals(TST_VAL, b.getProperty("test").toString()); + } + + @Test + public void testUpdateProperty() { + b.addProperty("test", TST_VAL); + assertEquals(TST_VAL, b.getProperty("test").toString()); + b.updateProperty("test", "new value"); + assertEquals("new value", b.getProperty("test").toString()); + } + + @Test + public void testSubscribe() { + String key = "subtst"; + + b.addProperty(key, "test"); + b.subscribe(key, mcl); + assertNull(notifyKey); + assertNull(notifyValue); + + b.updateProperty(key, "test2"); + assertEquals(key, notifyKey); + assertEquals("test2", notifyValue.toString()); + + b.updateProperty(key, "newTest"); + assertEquals(key, notifyKey); + assertEquals("newTest", notifyValue.toString()); + } + + @Test + public void testUnsubscribe() { + String key = "unsubtst"; + String tstVal = "unsubtstvalue"; + b.subscribe(key, mcl); + b.updateProperty(key, tstVal); + b.unsubscribe(key, mcl); + + b.updateProperty(key, "newvalue"); + assertEquals("newvalue", b.getProperty(key).toString()); + assertEquals(key, notifyKey); + assertEquals(tstVal, notifyValue.toString()); + } + + @Test + public void testUpdateDouble() { + String key = "doubletst"; + Double val = 15.5; + + b.addProperty(key, val); + assertEquals(16.5, b.updateDouble(key, 1.0)); + assertEquals(16.5, b.getDouble(key, -1.0)); + + assertEquals(13.3, b.updateDouble(key, -3.2)); + assertEquals(13.3, b.getDouble(key, -1.0)); + + assertEquals(-16.7, b.updateDouble(key, -30)); + assertEquals(-16.7, b.getDouble(key, -1.0)); + } + +} diff --git a/test/PointsOfInterestTest.java b/test/PointsOfInterestTest.java index 2f1df8d57..e901bf9af 100644 --- a/test/PointsOfInterestTest.java +++ b/test/PointsOfInterestTest.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import input.WKTMapReader; import java.io.File; @@ -19,199 +19,199 @@ import movement.map.SimMap; import core.Coord; import core.Settings; - -/** - * Test for selecting Points Of Interest from different node groups. - * Tests that the probability of getting a node from a specific group is - * approximately same as the defined probability. - */ -public class PointsOfInterestTest extends TestCase { - - /* Topology: n7--n5 - * | | - * n1--n2--n6--n3 - * | - * n4 - */ - private static final String MAP_DATA = - // n1 n2 n6 n3 - "LINESTRING (1.0 1.0, 2.0 1.0, 3.0 1.0, 4.0 1.0) \n" + - // n1 n4 - "LINESTRING (1.0 1.0, 1.0 2.0)\n"; - - private static final String MAP_DATA2 = - // n2 n7 n5 n6 - "LINESTRING (2.0 1.0, 2.0 0.0, 3.0 0.0, 3.0 1.0)\n"; - - private static final String[] POINTS_IN_MAP = { - "POINT (1.0 1.0)\n POINT (2.0 1.0)", - "POINT (4.0 1.0)\n POINT (1.0 2.0)", - "POINT (3.0 1.0)\n" - }; - - private static final Coord[][] COORDS_IN_MAP = { - {new Coord(1,1), new Coord(2,1)}, - {new Coord(4,1), new Coord(1,2)}, - {new Coord(3,1)} - }; - - private PointsOfInterest pois; - private int nrofMapNodes; - - protected void setUpWith(double[] poiProbs, int rngSeed, int [] okNodes) - throws Exception { - super.setUp(); - - Settings.init(null); - StringReader input = new StringReader(MAP_DATA); - - WKTMapReader reader = new WKTMapReader(true); - try { - reader.addPaths(input, 1); - input = new StringReader(MAP_DATA2); - reader.addPaths(input, 2); - } catch (IOException e) { - fail(e.toString()); - } - - SimMap map = reader.getMap(); - this.nrofMapNodes = map.getNodes().size(); - - File[] poiFiles = new File[POINTS_IN_MAP.length]; - for (int i=0; i path) { - int i; - assertEquals(realPath.length, path.size() + 1); - - for (i=0; i12->13->14->20 */ - oracle.addEntry(45, 3, 12, 2); - oracle.addEntry(50, 12, 13, 2); - oracle.addEntry(55, 13, 14, 2); - oracle.addEntry(57, 14, 20, 2); - comparePaths(new int[]{1,3,12,13,14,20}, d.getShortestPath(1, 20, 0)); - - /* misses the first hop to 3, takes direct late */ - comparePaths(new int[]{1, 20}, d.getShortestPath(1, 20, 30)); - - /* starts directly at 3 but too late for multihop */ - oracle.addEntry(55, 3, 11, 5); - comparePaths(new int[]{3, 11, 20}, d.getShortestPath(3, 20, 50)); - - /* starts directly at 3, early enough for multihop */ - comparePaths(new int[]{3,12,13,14,20}, d.getShortestPath(3, 20, 40)); - } - -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import java.util.List; + +import routing.schedule.ScheduleDijkstra; +import routing.schedule.ScheduleOracle; +import routing.schedule.ScheduleEntry; +import junit.framework.TestCase; + +public class ScheduleDijkstraTest extends TestCase { + + ScheduleOracle oracle; + ScheduleDijkstra d; + + protected void setUp() throws Exception { + super.setUp(); + oracle = new ScheduleOracle(); + d = new ScheduleDijkstra(oracle); + + oracle.addEntry(10, 1, 2, 10); + oracle.addEntry(20, 1, 3, 10); + oracle.addEntry(20, 1, 4, 10); + oracle.addEntry(30, 1, 5, 10); + } + + private void comparePaths(int realPath[], List path) { + int i; + assertEquals(realPath.length, path.size() + 1); + + for (i=0; i12->13->14->20 */ + oracle.addEntry(45, 3, 12, 2); + oracle.addEntry(50, 12, 13, 2); + oracle.addEntry(55, 13, 14, 2); + oracle.addEntry(57, 14, 20, 2); + comparePaths(new int[]{1,3,12,13,14,20}, d.getShortestPath(1, 20, 0)); + + /* misses the first hop to 3, takes direct late */ + comparePaths(new int[]{1, 20}, d.getShortestPath(1, 20, 30)); + + /* starts directly at 3 but too late for multihop */ + oracle.addEntry(55, 3, 11, 5); + comparePaths(new int[]{3, 11, 20}, d.getShortestPath(3, 20, 50)); + + /* starts directly at 3, early enough for multihop */ + comparePaths(new int[]{3,12,13,14,20}, d.getShortestPath(3, 20, 40)); + } + +} diff --git a/test/ScheduledUpdatesQueueTest.java b/test/ScheduledUpdatesQueueTest.java index f3a3733dc..43c11e609 100644 --- a/test/ScheduledUpdatesQueueTest.java +++ b/test/ScheduledUpdatesQueueTest.java @@ -1,110 +1,110 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package test; - -import input.ScheduledUpdatesQueue; -import junit.framework.TestCase; -import core.SimClock; - -/** - * Tests for the ScheduledUpdatesQueue - */ -public class ScheduledUpdatesQueueTest extends TestCase { - private static double MAX = Double.MAX_VALUE; - private ScheduledUpdatesQueue suq; - private SimClock sc = SimClock.getInstance(); - - protected void setUp() throws Exception { - super.setUp(); - SimClock.reset(); - suq = new ScheduledUpdatesQueue(); - } - - public void testUpdates() { - assertEquals(MAX, suq.nextEventsTime()); - suq.addUpdate(1); - suq.addUpdate(1.5); - suq.addUpdate(20); - suq.addUpdate(3); - suq.addUpdate(0); - suq.addUpdate(5.3); - - assertEquals(0.0, suq.nextEventsTime()); - assertEquals(0.0, suq.nextEvent().getTime()); - - assertEquals(1.0, suq.nextEventsTime()); - assertEquals(1.0, suq.nextEventsTime()); // twice the same request - assertEquals(1.0, suq.nextEvent().getTime()); - - assertEquals(1.5, suq.nextEvent().getTime()); - assertEquals(3.0, suq.nextEvent().getTime()); - assertEquals(5.3, suq.nextEvent().getTime()); - assertEquals(20.0, suq.nextEvent().getTime()); - - assertEquals(MAX, suq.nextEventsTime()); - assertEquals(MAX, suq.nextEvent().getTime()); - } - - public void testInterlavedRequests() { - suq.addUpdate(4); - suq.addUpdate(7); - suq.addUpdate(9); - - sc.setTime(1.0); - assertEquals(4.0, suq.nextEvent().getTime()); - - suq.addUpdate(8.5); - - suq.addUpdate(3); // to the top - assertEquals(3.0, suq.nextEvent().getTime()); - - suq.addUpdate(10); // to the bottom - sc.setTime(4.0); - assertEquals(7.0, suq.nextEvent().getTime()); - - sc.setTime(7.5); - assertEquals(8.5, suq.nextEvent().getTime()); - sc.setTime(8.8); - assertEquals(9.0, suq.nextEvent().getTime()); - sc.setTime(9.8); - assertEquals(10.0, suq.nextEvent().getTime()); - sc.setTime(15); - assertEquals(MAX, suq.nextEvent().getTime()); - } - - public void testNegativeAndZeroValues() { - suq.addUpdate(3.2); - suq.addUpdate(-2.1); - suq.addUpdate(0); - suq.addUpdate(15); - suq.addUpdate(-4); - suq.addUpdate(0.1); - - sc.setTime(-5); - - assertEquals(-4.0, suq.nextEvent().getTime()); - assertEquals(-2.1, suq.nextEvent().getTime()); - assertEquals(0.0, suq.nextEvent().getTime()); - assertEquals(0.1, suq.nextEvent().getTime()); - assertEquals(3.2, suq.nextEvent().getTime()); - assertEquals(15.0, suq.nextEvent().getTime()); - assertEquals(MAX, suq.nextEvent().getTime()); - } - - public void testDuplicateValues() { - suq.addUpdate(4.0); - suq.addUpdate(5.0); - suq.addUpdate(4.0); // these should be merged to the first value - suq.addUpdate(4.0); - suq.addUpdate(1.0); - suq.addUpdate(1.0); - suq.addUpdate(8.0); - - assertEquals(1.0, suq.nextEvent().getTime()); - assertEquals(4.0, suq.nextEvent().getTime()); - assertEquals(5.0, suq.nextEvent().getTime()); - assertEquals(8.0, suq.nextEvent().getTime()); - } -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import input.ScheduledUpdatesQueue; +import junit.framework.TestCase; +import core.SimClock; + +/** + * Tests for the ScheduledUpdatesQueue + */ +public class ScheduledUpdatesQueueTest extends TestCase { + private static double MAX = Double.MAX_VALUE; + private ScheduledUpdatesQueue suq; + private SimClock sc = SimClock.getInstance(); + + protected void setUp() throws Exception { + super.setUp(); + SimClock.reset(); + suq = new ScheduledUpdatesQueue(); + } + + public void testUpdates() { + assertEquals(MAX, suq.nextEventsTime()); + suq.addUpdate(1); + suq.addUpdate(1.5); + suq.addUpdate(20); + suq.addUpdate(3); + suq.addUpdate(0); + suq.addUpdate(5.3); + + assertEquals(0.0, suq.nextEventsTime()); + assertEquals(0.0, suq.nextEvent().getTime()); + + assertEquals(1.0, suq.nextEventsTime()); + assertEquals(1.0, suq.nextEventsTime()); // twice the same request + assertEquals(1.0, suq.nextEvent().getTime()); + + assertEquals(1.5, suq.nextEvent().getTime()); + assertEquals(3.0, suq.nextEvent().getTime()); + assertEquals(5.3, suq.nextEvent().getTime()); + assertEquals(20.0, suq.nextEvent().getTime()); + + assertEquals(MAX, suq.nextEventsTime()); + assertEquals(MAX, suq.nextEvent().getTime()); + } + + public void testInterlavedRequests() { + suq.addUpdate(4); + suq.addUpdate(7); + suq.addUpdate(9); + + sc.setTime(1.0); + assertEquals(4.0, suq.nextEvent().getTime()); + + suq.addUpdate(8.5); + + suq.addUpdate(3); // to the top + assertEquals(3.0, suq.nextEvent().getTime()); + + suq.addUpdate(10); // to the bottom + sc.setTime(4.0); + assertEquals(7.0, suq.nextEvent().getTime()); + + sc.setTime(7.5); + assertEquals(8.5, suq.nextEvent().getTime()); + sc.setTime(8.8); + assertEquals(9.0, suq.nextEvent().getTime()); + sc.setTime(9.8); + assertEquals(10.0, suq.nextEvent().getTime()); + sc.setTime(15); + assertEquals(MAX, suq.nextEvent().getTime()); + } + + public void testNegativeAndZeroValues() { + suq.addUpdate(3.2); + suq.addUpdate(-2.1); + suq.addUpdate(0); + suq.addUpdate(15); + suq.addUpdate(-4); + suq.addUpdate(0.1); + + sc.setTime(-5); + + assertEquals(-4.0, suq.nextEvent().getTime()); + assertEquals(-2.1, suq.nextEvent().getTime()); + assertEquals(0.0, suq.nextEvent().getTime()); + assertEquals(0.1, suq.nextEvent().getTime()); + assertEquals(3.2, suq.nextEvent().getTime()); + assertEquals(15.0, suq.nextEvent().getTime()); + assertEquals(MAX, suq.nextEvent().getTime()); + } + + public void testDuplicateValues() { + suq.addUpdate(4.0); + suq.addUpdate(5.0); + suq.addUpdate(4.0); // these should be merged to the first value + suq.addUpdate(4.0); + suq.addUpdate(1.0); + suq.addUpdate(1.0); + suq.addUpdate(8.0); + + assertEquals(1.0, suq.nextEvent().getTime()); + assertEquals(4.0, suq.nextEvent().getTime()); + assertEquals(5.0, suq.nextEvent().getTime()); + assertEquals(8.0, suq.nextEvent().getTime()); + } +} diff --git a/test/SettingsTest.java b/test/SettingsTest.java index 4212238f9..a9b886769 100644 --- a/test/SettingsTest.java +++ b/test/SettingsTest.java @@ -1,219 +1,219 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import java.io.File; import java.io.PrintWriter; import junit.framework.TestCase; import core.Settings; - -/** - * Tests Settings class' different setting getting methods - */ -public class SettingsTest extends TestCase { - private static final String IRS_S = "invalidRunSetting"; - - private static final String CSV_RS_S = "csvRunSetting"; - private static final int[] CSV_RS_V = {1,2,3,4}; - - private static final String TST = "tstSetting"; - private static final String TST_RES = "tst"; - private static final String[] INPUT = { - "Ns.setting1 = 1", - "Ns.setting2 = true", - TST + " = " + TST_RES, - "tstSetting2 = tst2", - "double = 1.1", - "csvDoubles = 1.1,2.2,3.3", - "csvInts 1,2,3", - "booleanTrue = true", - "booleanFalse = false", - "int = 1", - "runSetting = [val1 ; val2;val3; val4 ]", - IRS_S + " = [val1 ; val2", - CSV_RS_S + " = [" + CSV_RS_V[0]+","+CSV_RS_V[1]+";"+CSV_RS_V[2]+","+CSV_RS_V[3]+"]", - "Ns.runSetting = [ ; ; 2; ]", - "DefNs.runSetting = 1" - - }; - - private String RS_S = "runSetting"; - - - private Settings s; - - protected void setUp() throws Exception { - super.setUp(); - File tempFile = File.createTempFile("settingsTest", ".tmp"); - tempFile.deleteOnExit(); - - PrintWriter out = new PrintWriter(tempFile); - - for (String s : INPUT) { - out.println(s); - } - out.close(); - - Settings.init(tempFile.getAbsolutePath()); - s = new Settings(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - Settings.setRunIndex(0); - } - - - public void testContains() { - assertTrue(s.contains("Ns.setting1")); - assertTrue(s.contains("Ns.setting2")); - } - - public void testGetSetting() { - assertEquals("1", s.getSetting("Ns.setting1")); - assertEquals("true", s.getSetting("Ns.setting2")); - } - - public void testGetDouble() { - assertEquals(1.1, s.getDouble("double")); - } - - public void testGetCsvSetting() { - String[] csv = s.getCsvSetting("csvInts",3); - assertEquals(csv.length, 3); - assertEquals("1",csv[0]); - assertEquals("2",csv[1]); - assertEquals("3",csv[2]); - } - - public void testGetCsvDoubles() { - double[] csv = s.getCsvDoubles("csvDoubles",3); - assertEquals(csv.length, 3); - assertEquals(1.1,csv[0]); - assertEquals(2.2,csv[1]); - assertEquals(3.3,csv[2]); - } - - public void testGetCsvDoublesUnknownAmount() { - double[] csv = s.getCsvDoubles("csvDoubles"); - assertEquals(csv.length, 3); - assertEquals(1.1,csv[0]); - assertEquals(2.2,csv[1]); - assertEquals(3.3,csv[2]); - } - - public void testGetCsvInts() { - int[] csv = s.getCsvInts("csvInts",3); - assertEquals(csv.length, 3); - assertEquals(1,csv[0]); - assertEquals(2,csv[1]); - assertEquals(3,csv[2]); - } - - public void testGetCsvIntsUnknownAmount() { - int[] csv = s.getCsvInts("csvInts"); - assertEquals(csv.length, 3); - assertEquals(1,csv[0]); - assertEquals(2,csv[1]); - assertEquals(3,csv[2]); - } - - public void testGetInt() { - assertEquals(1,s.getInt("int")); - } - - public void testGetBoolean() { - assertTrue(s.getBoolean("booleanTrue")); - assertFalse(s.getBoolean("booleanFalse")); - } - - public void testCreateIntializedObject() { - Object o = s.createIntializedObject("movement.RandomWaypoint"); - assertTrue(o instanceof movement.RandomWaypoint); - } - - - public void testValueFillString() { - String test = "1-%%tstSetting%%-2-%%tstSetting2%%"; - String result = s.valueFillString(test); - assertEquals("1-tst-2-tst2",result); - - result = s.valueFillString("%%"+TST+"%%-aaa"); - assertEquals(TST_RES + "-aaa",result); - - result = s.valueFillString("%%"+TST+"%%"); - assertEquals(TST_RES,result); - } - - public void testRunIndex() { - assertEquals(s.getSetting(RS_S), "val1"); - Settings.setRunIndex(1); - assertEquals(s.getSetting(RS_S), "val2"); - Settings.setRunIndex(2); - assertEquals(s.getSetting(RS_S), "val3"); - Settings.setRunIndex(3); - assertEquals(s.getSetting(RS_S), "val4"); - Settings.setRunIndex(4); - assertEquals(s.getSetting(RS_S), "val1"); // should wrap around - Settings.setRunIndex(5); - assertEquals(s.getSetting(RS_S), "val2"); - } - - public void testRunIndexContains() { - assertFalse(s.contains("Ns.runSetting")); - Settings.setRunIndex(2); - assertTrue(s.contains("Ns.runSetting")); - } - - /** - * Test filling empty values of run index from secondary namespace - */ - public void testEmptyRunIndex() { - String rs = "runSetting"; - Settings s = new Settings("Ns"); - s.setSecondaryNamespace("DefNs"); - assertEquals(s.getInt(rs), 1); - Settings.setRunIndex(1); - assertEquals(s.getInt(rs), 1); - - Settings.setRunIndex(2); - assertEquals(s.getInt(rs), 2); // the only defined value - - Settings.setRunIndex(3); - assertEquals(s.getInt(rs), 1); - } - - public void testRunIndexCSVs() { - // test CSVs - int [] vals = s.getCsvInts(CSV_RS_S, 2); - assertEquals(CSV_RS_V[0],vals[0]); - assertEquals(CSV_RS_V[1],vals[1]); - - Settings.setRunIndex(1); - vals = s.getCsvInts(CSV_RS_S, 2); - assertEquals(CSV_RS_V[2],vals[0]); - assertEquals(CSV_RS_V[3],vals[1]); - - Settings.setRunIndex(2); // wrap around - vals = s.getCsvInts(CSV_RS_S, 2); - assertEquals(CSV_RS_V[0],vals[0]); - assertEquals(CSV_RS_V[1],vals[1]); - } - - public void testInvalidRunIndex() { - assertEquals("[val1 ; val2",s.getSetting(IRS_S)); - } - - /** - * Tests disabled run-specific variables - */ - public void testNoRun() { - Settings.setRunIndex(-1); - assertEquals("[val1 ; val2;val3; val4 ]", s.getSetting(RS_S)); - } - -} + +/** + * Tests Settings class' different setting getting methods + */ +public class SettingsTest extends TestCase { + private static final String IRS_S = "invalidRunSetting"; + + private static final String CSV_RS_S = "csvRunSetting"; + private static final int[] CSV_RS_V = {1,2,3,4}; + + private static final String TST = "tstSetting"; + private static final String TST_RES = "tst"; + private static final String[] INPUT = { + "Ns.setting1 = 1", + "Ns.setting2 = true", + TST + " = " + TST_RES, + "tstSetting2 = tst2", + "double = 1.1", + "csvDoubles = 1.1,2.2,3.3", + "csvInts 1,2,3", + "booleanTrue = true", + "booleanFalse = false", + "int = 1", + "runSetting = [val1 ; val2;val3; val4 ]", + IRS_S + " = [val1 ; val2", + CSV_RS_S + " = [" + CSV_RS_V[0]+","+CSV_RS_V[1]+";"+CSV_RS_V[2]+","+CSV_RS_V[3]+"]", + "Ns.runSetting = [ ; ; 2; ]", + "DefNs.runSetting = 1" + + }; + + private String RS_S = "runSetting"; + + + private Settings s; + + protected void setUp() throws Exception { + super.setUp(); + File tempFile = File.createTempFile("settingsTest", ".tmp"); + tempFile.deleteOnExit(); + + PrintWriter out = new PrintWriter(tempFile); + + for (String s : INPUT) { + out.println(s); + } + out.close(); + + Settings.init(tempFile.getAbsolutePath()); + s = new Settings(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + Settings.setRunIndex(0); + } + + + public void testContains() { + assertTrue(s.contains("Ns.setting1")); + assertTrue(s.contains("Ns.setting2")); + } + + public void testGetSetting() { + assertEquals("1", s.getSetting("Ns.setting1")); + assertEquals("true", s.getSetting("Ns.setting2")); + } + + public void testGetDouble() { + assertEquals(1.1, s.getDouble("double")); + } + + public void testGetCsvSetting() { + String[] csv = s.getCsvSetting("csvInts",3); + assertEquals(csv.length, 3); + assertEquals("1",csv[0]); + assertEquals("2",csv[1]); + assertEquals("3",csv[2]); + } + + public void testGetCsvDoubles() { + double[] csv = s.getCsvDoubles("csvDoubles",3); + assertEquals(csv.length, 3); + assertEquals(1.1,csv[0]); + assertEquals(2.2,csv[1]); + assertEquals(3.3,csv[2]); + } + + public void testGetCsvDoublesUnknownAmount() { + double[] csv = s.getCsvDoubles("csvDoubles"); + assertEquals(csv.length, 3); + assertEquals(1.1,csv[0]); + assertEquals(2.2,csv[1]); + assertEquals(3.3,csv[2]); + } + + public void testGetCsvInts() { + int[] csv = s.getCsvInts("csvInts",3); + assertEquals(csv.length, 3); + assertEquals(1,csv[0]); + assertEquals(2,csv[1]); + assertEquals(3,csv[2]); + } + + public void testGetCsvIntsUnknownAmount() { + int[] csv = s.getCsvInts("csvInts"); + assertEquals(csv.length, 3); + assertEquals(1,csv[0]); + assertEquals(2,csv[1]); + assertEquals(3,csv[2]); + } + + public void testGetInt() { + assertEquals(1,s.getInt("int")); + } + + public void testGetBoolean() { + assertTrue(s.getBoolean("booleanTrue")); + assertFalse(s.getBoolean("booleanFalse")); + } + + public void testCreateIntializedObject() { + Object o = s.createIntializedObject("movement.RandomWaypoint"); + assertTrue(o instanceof movement.RandomWaypoint); + } + + + public void testValueFillString() { + String test = "1-%%tstSetting%%-2-%%tstSetting2%%"; + String result = s.valueFillString(test); + assertEquals("1-tst-2-tst2",result); + + result = s.valueFillString("%%"+TST+"%%-aaa"); + assertEquals(TST_RES + "-aaa",result); + + result = s.valueFillString("%%"+TST+"%%"); + assertEquals(TST_RES,result); + } + + public void testRunIndex() { + assertEquals(s.getSetting(RS_S), "val1"); + Settings.setRunIndex(1); + assertEquals(s.getSetting(RS_S), "val2"); + Settings.setRunIndex(2); + assertEquals(s.getSetting(RS_S), "val3"); + Settings.setRunIndex(3); + assertEquals(s.getSetting(RS_S), "val4"); + Settings.setRunIndex(4); + assertEquals(s.getSetting(RS_S), "val1"); // should wrap around + Settings.setRunIndex(5); + assertEquals(s.getSetting(RS_S), "val2"); + } + + public void testRunIndexContains() { + assertFalse(s.contains("Ns.runSetting")); + Settings.setRunIndex(2); + assertTrue(s.contains("Ns.runSetting")); + } + + /** + * Test filling empty values of run index from secondary namespace + */ + public void testEmptyRunIndex() { + String rs = "runSetting"; + Settings s = new Settings("Ns"); + s.setSecondaryNamespace("DefNs"); + assertEquals(s.getInt(rs), 1); + Settings.setRunIndex(1); + assertEquals(s.getInt(rs), 1); + + Settings.setRunIndex(2); + assertEquals(s.getInt(rs), 2); // the only defined value + + Settings.setRunIndex(3); + assertEquals(s.getInt(rs), 1); + } + + public void testRunIndexCSVs() { + // test CSVs + int [] vals = s.getCsvInts(CSV_RS_S, 2); + assertEquals(CSV_RS_V[0],vals[0]); + assertEquals(CSV_RS_V[1],vals[1]); + + Settings.setRunIndex(1); + vals = s.getCsvInts(CSV_RS_S, 2); + assertEquals(CSV_RS_V[2],vals[0]); + assertEquals(CSV_RS_V[3],vals[1]); + + Settings.setRunIndex(2); // wrap around + vals = s.getCsvInts(CSV_RS_S, 2); + assertEquals(CSV_RS_V[0],vals[0]); + assertEquals(CSV_RS_V[1],vals[1]); + } + + public void testInvalidRunIndex() { + assertEquals("[val1 ; val2",s.getSetting(IRS_S)); + } + + /** + * Tests disabled run-specific variables + */ + public void testNoRun() { + Settings.setRunIndex(-1); + assertEquals("[val1 ; val2;val3; val4 ]", s.getSetting(RS_S)); + } + +} diff --git a/test/StationaryMovement.java b/test/StationaryMovement.java index 5ea0bbaa4..6c9ace8a6 100644 --- a/test/StationaryMovement.java +++ b/test/StationaryMovement.java @@ -1,62 +1,62 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import movement.MovementModel; import movement.Path; import core.Coord; - -/** - * A dummy stationary "movement" model where nodes do not move for testing - * purposes - */ -public class StationaryMovement extends MovementModel { - private Coord loc; - - public StationaryMovement(Coord location) { - if (location == null) { - this.loc = new Coord(0,0); - } - else { - this.loc = location; - } - } - - /** - * Returns the only location of this movement model - * @return the only location of this movement model - */ - @Override - public Coord getInitialLocation() { - return loc; - } - - @Override - public boolean isActive() { - return true; - } - - /** - * Returns a single coordinate path (using the only possible coordinate) - * @return a single coordinate path - */ - @Override - public Path getPath() { - Path p = new Path(0); - p.addWaypoint(loc); - return p; - } - - @Override - public double nextPathAvailable() { - return Double.MAX_VALUE; // no new paths available - } - - @Override - public StationaryMovement replicate() { - return new StationaryMovement(loc); - } - -} + +/** + * A dummy stationary "movement" model where nodes do not move for testing + * purposes + */ +public class StationaryMovement extends MovementModel { + private Coord loc; + + public StationaryMovement(Coord location) { + if (location == null) { + this.loc = new Coord(0,0); + } + else { + this.loc = location; + } + } + + /** + * Returns the only location of this movement model + * @return the only location of this movement model + */ + @Override + public Coord getInitialLocation() { + return loc; + } + + @Override + public boolean isActive() { + return true; + } + + /** + * Returns a single coordinate path (using the only possible coordinate) + * @return a single coordinate path + */ + @Override + public Path getPath() { + Path p = new Path(0); + p.addWaypoint(loc); + return p; + } + + @Override + public double nextPathAvailable() { + return Double.MAX_VALUE; // no new paths available + } + + @Override + public StationaryMovement replicate() { + return new StationaryMovement(loc); + } + +} diff --git a/test/TestDTNHost.java b/test/TestDTNHost.java index 9f8e4f30f..33b1362a8 100644 --- a/test/TestDTNHost.java +++ b/test/TestDTNHost.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import java.util.List; import routing.PassiveRouter; @@ -14,13 +14,13 @@ import core.NetworkInterface; import core.Settings; import core.SimClock; - -/** + +/** * A test stub of DTNHost for testing. All fields are public so they can be - * easily read from test cases. - */ + * easily read from test cases. + */ public class TestDTNHost extends DTNHost { - public double lastUpdate = 0; + public double lastUpdate = 0; public int nrofConnect = 0; public int nrofUpdate = 0; public Message recvMessage; @@ -28,48 +28,48 @@ public class TestDTNHost extends DTNHost { public String abortedId; public DTNHost abortedFrom; public int abortedBytesRemaining; - + public String transferredId; public DTNHost transferredFrom; - - public TestDTNHost(List li, + + public TestDTNHost(List li, ModuleCommunicationBus comBus, Settings testSettings) { - super(null,null,"TST", li, comBus, - new StationaryMovement(new Coord(0,0)), + super(null,null,"TST", li, comBus, + new StationaryMovement(new Coord(0,0)), new PassiveRouter( (testSettings == null ? new TestSettings() : testSettings))); } - + @Override public void connect(DTNHost anotherHost) { this.nrofConnect++; } - + @Override public void update(boolean up) { this.nrofUpdate++; this.lastUpdate = SimClock.getTime(); } - + @Override public int receiveMessage(Message m, DTNHost from) { this.recvMessage = m; this.recvFrom = from; return routing.MessageRouter.RCV_OK; } - + @Override public void messageAborted(String id, DTNHost from, int bytesRemaining) { this.abortedId = id; this.abortedFrom = from; this.abortedBytesRemaining = bytesRemaining; } - + @Override public void messageTransferred(String id, DTNHost from) { this.transferredId = id; this.transferredFrom = from; } -} +} diff --git a/test/TestInterface.java b/test/TestInterface.java index 490f2554f..91dc9fe52 100644 --- a/test/TestInterface.java +++ b/test/TestInterface.java @@ -1,90 +1,90 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package test; - -import core.CBRConnection; -import core.Connection; -import core.DTNHost; -import core.NetworkInterface; -import core.Settings; - -public class TestInterface extends NetworkInterface { - - public TestInterface(Settings s) { - super(s); - } - - public TestInterface(TestInterface ti) { - super(ti); - } - - /** - * Replication function - */ - public NetworkInterface replicate() { - return new TestInterface(this); - } - - /** - * Gives the currentTransmit Speed - */ - public int getTransmitSpeed() { - return transmitSpeed; - } - - /** - * Gives the currentTransmit Range - */ - public double getTransmitRange() { - return transmitRange; - } - - /** - * Connects the interface to another interface. - * - * Overload this in a derived class. Check the requirements for - * the connection to work in the derived class, then call - * connect(Connection, NetworkInterface) for the actual connection. - * @param anotherInterface The host to connect to - */ - public void connect(NetworkInterface anotherInterface) { - Connection con = new CBRConnection(this.getHost(),this, - anotherInterface.getHost(),anotherInterface, transmitSpeed); - this.connect(con, anotherInterface); - } - - /** - * Updates the state of current connections (ie tears down connections - * that are out of range, recalculates transmission speeds etc.). - */ - public void update() { - for (int i=0; i conListeners; - private List msgListeners; - private String groupId = "h"; - private List allHosts; - private MessageRouter mr; - + +/** + * Generic convenience methods for tests. + */ +public class TestUtils { + + private List conListeners; + private List msgListeners; + private String groupId = "h"; + private List allHosts; + private MessageRouter mr; + private ModuleCommunicationBus comBus; private TestSettings settings; - + public static String IFACE_NS = "interface"; - - /** - * Creates a test utils object suitable for creating new hosts. - * @param cl Connection listeners for the hosts - * @param ml Message -"- - * @param settings Setting object given to message router - */ - public TestUtils(List cl, List ml, - TestSettings settings) { - this.conListeners = cl; - this.msgListeners = ml; + + /** + * Creates a test utils object suitable for creating new hosts. + * @param cl Connection listeners for the hosts + * @param ml Message -"- + * @param settings Setting object given to message router + */ + public TestUtils(List cl, List ml, + TestSettings settings) { + this.conListeners = cl; + this.msgListeners = ml; this.allHosts = new ArrayList(); - this.settings = settings; - this.mr = new PassiveRouter(settings); - - this.comBus = new ModuleCommunicationBus(); - } - - public void setMessageRouterProto(MessageRouter mr) { - this.mr = mr; - } - - /** - * @param conListeners the ConnectionListeners to set - */ - public void setConListeners(List conListeners) { - this.conListeners = conListeners; - } - - /** - * @param groupId the groupId to set - */ - public void setGroupId(String groupId) { - this.groupId = groupId; - } - - /** - * @param msgListeners the MessageListeners to set - */ - public void setMsgListeners(List msgListeners) { - this.msgListeners = msgListeners; - } - - /** - * @param transmitRange the transmitRange to set - */ - public void setTransmitRange(double transmitRange) { - this.comBus.updateProperty(NetworkInterface.RANGE_ID, transmitRange); - } - - /** - * Creates a host to a location with stationary movement model and - * MessageRouter router. - * @param loc The location of the host - * @param name Name of the host (or null for default) - * @return The new host - */ - public DTNHost createHost(Coord loc, String name) { - MovementModel mmProto = new StationaryMovement(loc); - return createHost(mmProto, name); - } - - /** - * Creates a host with defined movement model - * @param mmProto The prototype of the movement model - * @param name name of the host - * @return the host - */ + this.settings = settings; + this.mr = new PassiveRouter(settings); + + this.comBus = new ModuleCommunicationBus(); + } + + public void setMessageRouterProto(MessageRouter mr) { + this.mr = mr; + } + + /** + * @param conListeners the ConnectionListeners to set + */ + public void setConListeners(List conListeners) { + this.conListeners = conListeners; + } + + /** + * @param groupId the groupId to set + */ + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + /** + * @param msgListeners the MessageListeners to set + */ + public void setMsgListeners(List msgListeners) { + this.msgListeners = msgListeners; + } + + /** + * @param transmitRange the transmitRange to set + */ + public void setTransmitRange(double transmitRange) { + this.comBus.updateProperty(NetworkInterface.RANGE_ID, transmitRange); + } + + /** + * Creates a host to a location with stationary movement model and + * MessageRouter router. + * @param loc The location of the host + * @param name Name of the host (or null for default) + * @return The new host + */ + public DTNHost createHost(Coord loc, String name) { + MovementModel mmProto = new StationaryMovement(loc); + return createHost(mmProto, name); + } + + /** + * Creates a host with defined movement model + * @param mmProto The prototype of the movement model + * @param name name of the host + * @return the host + */ public DTNHost createHost(MovementModel mmProto, String name) { if (settings.getNameSpace() == null) { settings.setNameSpace(IFACE_NS); @@ -108,41 +108,41 @@ public DTNHost createHost(MovementModel mmProto, String name) { settings.putSetting(NetworkInterface.TRANSMIT_RANGE_S, "1.0"); settings.putSetting(NetworkInterface.TRANSMIT_SPEED_S, "1"); } - + NetworkInterface ni = new TestInterface(settings); ni.setClisteners(conListeners); List li = new ArrayList(); li.add(ni); DTNHost host = new DTNHost(msgListeners, null, groupId, li, comBus, mmProto, mr); - if (name != null) { - host.setName(name); - } - - this.allHosts.add(host); - return host; - } - - /** - * Creates a host to a location with stationary movement model and - * default name. - * @param loc The location of the host - * @return The new host - */ - public DTNHost createHost(Coord loc) { - return this.createHost(loc, null); - } - - /** - * Creates a host to location (0,0) with stationary movement model - * and default name. - * @return The new host - */ - public DTNHost createHost() { - return this.createHost(new Coord(0,0)); - } - - public List getAllHosts() { - return this.allHosts; - } -} + if (name != null) { + host.setName(name); + } + + this.allHosts.add(host); + return host; + } + + /** + * Creates a host to a location with stationary movement model and + * default name. + * @param loc The location of the host + * @return The new host + */ + public DTNHost createHost(Coord loc) { + return this.createHost(loc, null); + } + + /** + * Creates a host to location (0,0) with stationary movement model + * and default name. + * @return The new host + */ + public DTNHost createHost() { + return this.createHost(new Coord(0,0)); + } + + public List getAllHosts() { + return this.allHosts; + } +} diff --git a/test/TotalContactTimeReportTest.java b/test/TotalContactTimeReportTest.java index a9d221703..3b1e83294 100644 --- a/test/TotalContactTimeReportTest.java +++ b/test/TotalContactTimeReportTest.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -16,123 +16,123 @@ import core.Coord; import core.DTNHost; import core.SimClock; - -public class TotalContactTimeReportTest extends TestCase { - private BufferedReader ctReader; - private File outFile; - private SimClock clock; - private TotalContactTimeReport ctr; - - private DTNHost h1, h2, h3; - private Coord c1 = new Coord(0,0); - private Coord c2 = new Coord(1,0); - private Coord c3 = new Coord(2,0); - private Coord away = new Coord(1000,1000); - - private final String SET_PREFIX = "TotalContactTimeReport."; - - protected void setUp() throws Exception { - super.setUp(); - SimClock.reset(); - outFile = File.createTempFile("cttest", ".tmp"); - outFile.deleteOnExit(); - - TestSettings ts = new TestSettings(); - ts.putSetting(SET_PREFIX + - report.Report.PRECISION_SETTING, "1"); // drop precision to 1 - ts.putSetting(SET_PREFIX + report.ContactTimesReport.GRANULARITY, "5"); - - ts.putSetting(SET_PREFIX + Report.OUTPUT_SETTING, - outFile.getAbsolutePath()); - - clock = SimClock.getInstance(); - ctr = new TotalContactTimeReport(); - - Vector cl = new Vector(); - cl.add(ctr); - TestUtils utils = new TestUtils(cl, null, ts); - - utils.setTransmitRange(3); // make sure everyone can connect - h1 = utils.createHost(c1); - h2 = utils.createHost(c2); - h3 = utils.createHost(c3); - } - - private void done() throws Exception { - ctr.done(); - ctReader = new BufferedReader(new FileReader(outFile)); - } - - public void testReport() throws Exception { - clock.advance(5); - h1.connect(h2); - clock.advance(10); - disc(h2); - ctr.updated(null); - h1.connect(h2); - clock.advance(1); - ctr.updated(null); // less time than granularity has passed -> suppress - clock.advance(4); - ctr.updated(null); // now should report - - checkValues(new String[] {"15.0 10.0", "20.0 15.0"}); - } - - public void testMultipleTimes() throws Exception { - clock.advance(10); - h1.connect(h2); - clock.advance(10); - disc(h2); - ctr.updated(null); - h2.connect(h3); - clock.advance(5); - ctr.updated(null); - - checkValues(new String[] {"20.0 10.0", "25.0 15.0"}); - } - - public void testOverlappingTimes() throws Exception { - clock.advance(5); - h1.connect(h2); - clock.advance(5); - ctr.updated(null); // h1-h2 connected for 5s -> @10: 5s - h2.connect(h3); - clock.advance(10); - ctr.updated(null); // h1-h2 for 15s and h2-h3 for 10s -> @20: 25s - h1.setLocation(away); - h1.update(true); // h1-h2 disconnected - clock.advance(10); - disc(h3); // h2-h3 connected for 20s + h1-h2 15s -> @30: 35s - ctr.updated(null); - clock.advance(10); - ctr.updated(null); // no more active connections -> should suppress this - - h2.connect(h3); - clock.advance(5); - ctr.updated(null); // h2-h3 5s -> @45: 40s - - checkValues(new String[] {"10.0 5.0", "20.0 25.0", "30.0 35.0", - "45.0 40.0"}); - } - - private void disc(DTNHost host) { - Coord loc = host.getLocation(); - host.setLocation(away); - host.update(true); - host.setLocation(loc); - } - - private void checkValues(String[] values) throws Exception { - done(); - // read header line away - assertTrue(ctReader.ready()); - assertEquals(TotalContactTimeReport.HEADER, ctReader.readLine()); - - for (String value : values) { - assertEquals(value,ctReader.readLine()); - } - assertEquals(null,ctReader.readLine()); // no more times left - - } - -} + +public class TotalContactTimeReportTest extends TestCase { + private BufferedReader ctReader; + private File outFile; + private SimClock clock; + private TotalContactTimeReport ctr; + + private DTNHost h1, h2, h3; + private Coord c1 = new Coord(0,0); + private Coord c2 = new Coord(1,0); + private Coord c3 = new Coord(2,0); + private Coord away = new Coord(1000,1000); + + private final String SET_PREFIX = "TotalContactTimeReport."; + + protected void setUp() throws Exception { + super.setUp(); + SimClock.reset(); + outFile = File.createTempFile("cttest", ".tmp"); + outFile.deleteOnExit(); + + TestSettings ts = new TestSettings(); + ts.putSetting(SET_PREFIX + + report.Report.PRECISION_SETTING, "1"); // drop precision to 1 + ts.putSetting(SET_PREFIX + report.ContactTimesReport.GRANULARITY, "5"); + + ts.putSetting(SET_PREFIX + Report.OUTPUT_SETTING, + outFile.getAbsolutePath()); + + clock = SimClock.getInstance(); + ctr = new TotalContactTimeReport(); + + Vector cl = new Vector(); + cl.add(ctr); + TestUtils utils = new TestUtils(cl, null, ts); + + utils.setTransmitRange(3); // make sure everyone can connect + h1 = utils.createHost(c1); + h2 = utils.createHost(c2); + h3 = utils.createHost(c3); + } + + private void done() throws Exception { + ctr.done(); + ctReader = new BufferedReader(new FileReader(outFile)); + } + + public void testReport() throws Exception { + clock.advance(5); + h1.connect(h2); + clock.advance(10); + disc(h2); + ctr.updated(null); + h1.connect(h2); + clock.advance(1); + ctr.updated(null); // less time than granularity has passed -> suppress + clock.advance(4); + ctr.updated(null); // now should report + + checkValues(new String[] {"15.0 10.0", "20.0 15.0"}); + } + + public void testMultipleTimes() throws Exception { + clock.advance(10); + h1.connect(h2); + clock.advance(10); + disc(h2); + ctr.updated(null); + h2.connect(h3); + clock.advance(5); + ctr.updated(null); + + checkValues(new String[] {"20.0 10.0", "25.0 15.0"}); + } + + public void testOverlappingTimes() throws Exception { + clock.advance(5); + h1.connect(h2); + clock.advance(5); + ctr.updated(null); // h1-h2 connected for 5s -> @10: 5s + h2.connect(h3); + clock.advance(10); + ctr.updated(null); // h1-h2 for 15s and h2-h3 for 10s -> @20: 25s + h1.setLocation(away); + h1.update(true); // h1-h2 disconnected + clock.advance(10); + disc(h3); // h2-h3 connected for 20s + h1-h2 15s -> @30: 35s + ctr.updated(null); + clock.advance(10); + ctr.updated(null); // no more active connections -> should suppress this + + h2.connect(h3); + clock.advance(5); + ctr.updated(null); // h2-h3 5s -> @45: 40s + + checkValues(new String[] {"10.0 5.0", "20.0 25.0", "30.0 35.0", + "45.0 40.0"}); + } + + private void disc(DTNHost host) { + Coord loc = host.getLocation(); + host.setLocation(away); + host.update(true); + host.setLocation(loc); + } + + private void checkValues(String[] values) throws Exception { + done(); + // read header line away + assertTrue(ctReader.ready()); + assertEquals(TotalContactTimeReport.HEADER, ctReader.readLine()); + + for (String value : values) { + assertEquals(value,ctReader.readLine()); + } + assertEquals(null,ctReader.readLine()); // no more times left + + } + +} diff --git a/test/WKTPointReaderTest.java b/test/WKTPointReaderTest.java index 4977a8e4f..932f974c4 100644 --- a/test/WKTPointReaderTest.java +++ b/test/WKTPointReaderTest.java @@ -1,9 +1,9 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. + * Released under GPLv3. See LICENSE.txt for details. */ -package test; - +package test; + import input.WKTReader; import java.io.StringReader; @@ -11,38 +11,38 @@ import junit.framework.TestCase; import core.Coord; - -public class WKTPointReaderTest extends TestCase { - - private WKTReader r; - - private final String POINT_DATA = - "POINT (2552448.388211649 6673384.4020657055) \n"+ - "POINT (2552275.9398973365 6673509.820852942)\n"+ - "POINT (2552361.289603607 6673630.088457832)\n"+ - "LINESTRING (1.0 2.0, 2.0 3.0)\n"+ // should skip this line - "POINT (2552782.3212060533 6673285.5993876355)\n"; - - private final Coord[] POINTS = { - new Coord(2552448.388211649, 6673384.4020657055), - new Coord(2552275.9398973365, 6673509.820852942), - new Coord(2552361.289603607, 6673630.088457832), - new Coord(2552782.3212060533, 6673285.5993876355) - }; - - protected void setUp() throws Exception { - super.setUp(); - r = new WKTReader(); - } - - public void testReader() throws Exception { - StringReader input = new StringReader(POINT_DATA); - List coords = r.readPoints(input); - - assertEquals(POINTS.length, coords.size()); - - for (int i=0; i coords = r.readPoints(input); + + assertEquals(POINTS.length, coords.size()); + + for (int i=0; i nh) { - MapNode n1,n2,n3,n4,n5,n8,n9; - - // right amount of nodes? - assertEquals(NROF_TST_NODES, nh.size()); - - n1 = nh.get(n1c); - n2 = nh.get(n2c); - n3 = nh.get(new Coord(8,1)); - n4 = nh.get(new Coord(1,3)); - n5 = nh.get(new Coord(3,0)); - n8 = nh.get(new Coord(2,3)); - n9 = nh.get(n9c); - - // all nodes exist? - assertNotNull(n1); - assertNotNull(n2); - assertNotNull(n3); - assertNotNull(n4); - assertNotNull(n5); - assertNotNull(n8); - assertNotNull(n9); - - // nodes have correct amount of neighbors? - assertEquals(2, n1.getNeighbors().size()); - assertEquals(3, n2.getNeighbors().size()); - assertEquals(1, n3.getNeighbors().size()); - assertEquals(2, n4.getNeighbors().size()); - assertEquals(2, n5.getNeighbors().size()); - assertEquals(2, n8.getNeighbors().size()); - assertEquals(1, n9.getNeighbors().size()); - } - - public void testFromFile() throws IOException { - File wktFile = File.createTempFile("WKTReaderTest","tmp"); - wktFile.deleteOnExit(); - PrintWriter pw = new PrintWriter(wktFile); - WKTMapReader reader; - - pw.println(TST_TOPOLOGY); - pw.close(); - reader = setUpWith(new FileReader(wktFile)); - - basicNodesTests(reader); - topologyTest(reader.getNodesHash()); - } - - public void testMultiLineString() { - String multiline = "MULTILINESTRING ((1.0 1.0, 2.0 1.0, 3.0 1.0),"+ - "(1.0 1.0, 1.0 2.0))"; - StringReader input = new StringReader(multiline); - Map nh; - - WKTMapReader reader = setUpWith(input); - nh = reader.getNodesHash(); - - assertEquals(4, nh.size()); - } - - public void testReadContents() throws IOException { - String c1 = "lorem ipsum dolor sit amet"; - String c2 = "lorem ipsum\r\ndolor sit\n\r amet"; - String internal = "(lorem),(ipsum)"; - String cont = "ACTION ("+c1+")"; - String cont2 = "ACTION ("+c2+")"; - String cont3 = "MLS ("+internal+")"; - - WKTMapReader r = new WKTMapReader(true); - - StringReader s = new StringReader(cont3); - assertEquals(internal, r.readNestedContents(s)); - - s = new StringReader(cont); - assertEquals(c1,r.readNestedContents(s)); - - s = new StringReader(cont2); - // should convert newline to space - c2 = c2.replaceAll("(\r|\n)", " "); - assertEquals(c2,r.readNestedContents(s)); - } - - public void testMapOperations() { - String wkt = "LINESTRING (1.0 1.0, 2.0 5.0)\n" + - "LINESTRING (1.0 1.0, 1.0 3.0)\n"; - WKTMapReader reader = setUpWith(new StringReader(wkt)); - SimMap map = reader.getMap(); - - Coord max = map.getMaxBound(); - Coord min = map.getMinBound(); - - assertEquals(2.0, max.getX()); - assertEquals(5.0, max.getY()); - assertEquals(1.0, min.getX()); - assertEquals(1.0, min.getY()); - - map.translate(-1, -1); - max = map.getMaxBound(); - min = map.getMinBound(); - - assertEquals(1.0, max.getX()); - assertEquals(4.0, max.getY()); - assertEquals(0.0, min.getX()); - assertEquals(0.0, min.getY()); - - } - - public void testMultipleMapFiles() throws Exception { - File wktFile1 = File.createTempFile("WKTReaderTest","tmp"); - File wktFile2 = File.createTempFile("WKTReaderTest","tmp"); - File wktFile3 = File.createTempFile("WKTReaderTest","tmp"); - wktFile1.deleteOnExit(); - wktFile2.deleteOnExit(); - wktFile3.deleteOnExit(); - - PrintWriter pw = new PrintWriter(wktFile1); - pw.println(TST_TOPOLOGY); - pw.close(); - pw = new PrintWriter(wktFile2); - pw.println(ADD_TOPOLOGY); - pw.close(); - pw = new PrintWriter(wktFile3); - pw.println(ADD_TOPOLOGY2); - pw.close(); - - WKTMapReader reader = new WKTMapReader(true); - reader.addPaths(wktFile1, 1); - reader.addPaths(wktFile2, 2); - reader.addPaths(wktFile3, 31); - - basicNodesTests(reader); - - SimMap map = reader.getMap(); - - // n1 should be of type 1 - MapNode n1 = map.getNodeByCoord(n1c); - assertTrue(n1.isType(1)); - assertTrue(n1.isType(new int [] {2,1})); - assertFalse(n1.isType(2)); - - // n10 should be of type 2 - assertTrue(map.getNodeByCoord(n10c).isType(2)); - assertFalse(map.getNodeByCoord(n10c).isType(1)); - - // n9 should be type1, type2 and type31 - MapNode n9 = map.getNodeByCoord(n9c); - assertTrue(n9.isType(2)); - assertTrue(n9.isType(1)); - assertTrue(n9.isType(31)); - assertFalse(n9.isType(4)); - - assertTrue(n9.isType(new int [] {1,2,31})); - assertTrue(n9.isType(new int [] {5,2})); - assertTrue(n9.isType(new int [] {1,5})); - assertTrue(n9.isType(new int [] {5,7,31})); - assertFalse(n9.isType(new int [] {5,7,8})); - - // n11 should be only 31 - assertTrue(map.getNodeByCoord(n11c).isType(31)); - assertFalse(map.getNodeByCoord(n11c).isType(2)); - } - - private void basicNodesTests(WKTMapReader reader) { - Collection col = reader.getNodes(); - - // contains something - assertTrue(col.size() > 0); - - for (MapNode n : col) { - // no lonely nodes - assertTrue(n.getNeighbors().size() >= 1); - } - } - -} + +public class WKTReaderTest extends TestCase { + private WKTMapReader reader; + + + private final int NROF_TST_NODES = 9; + /* Topology: n6--n5 + * | | + * n1--n2--n7----n3 + * | + * n4--n8--n9 (-- n10; from ADD_TOPOLOGY) + * ( | + * n11; from ADD_TOPOLOGY2 ) + */ + // n1 n2 n7 n3 + private String TST_TOPOLOGY = "LINESTRING (1.0 1.0, 2.0 1.0, 3.0 1.0, 8.0 1.0) \n\r" + + // n1 n4 + "LINESTRING (1.0 1.0, 1.0 3.0)\n"+ + // n2 n6 n5 n7 + "LINESTRING (2.0 1.0, 2.0 0.0, 3.0 0.0, 3.0 1.0)\r\n"+ + "POINT (1.0 2.0)\n" + // should skip this line + // n4 n8 n8 n9 + "LINESTRING (1.0 3.0, 2.0 3.0) LINESTRING (2.0 3.0, 3.0 3.0)"; + + // n9 n10 + private String ADD_TOPOLOGY = "LINESTRING (3.0 3.0, 5.0 3.0)"; + // n9 n11 + private String ADD_TOPOLOGY2 = "LINESTRING (3.0 3.0, 3.0 5.0)"; + + + // coordinates of some map nodes + private Coord n1c = new Coord(1,1); + private Coord n2c = new Coord(2,1); + private Coord n9c = new Coord(3,3); + private Coord n10c = new Coord(5,3); + private Coord n11c = new Coord(3,5); + + + private WKTMapReader setUpWith(Reader input) { + reader = new WKTMapReader(true); + try { + reader.addPaths(input, 0); + } catch (IOException e) { + fail(e.toString()); + } + + return reader; + } + + public void testFromString() { + StringReader input = new StringReader(TST_TOPOLOGY); + + WKTMapReader reader = setUpWith(input); + basicNodesTests(reader); + topologyTest(reader.getNodesHash()); + } + + private void topologyTest(Map nh) { + MapNode n1,n2,n3,n4,n5,n8,n9; + + // right amount of nodes? + assertEquals(NROF_TST_NODES, nh.size()); + + n1 = nh.get(n1c); + n2 = nh.get(n2c); + n3 = nh.get(new Coord(8,1)); + n4 = nh.get(new Coord(1,3)); + n5 = nh.get(new Coord(3,0)); + n8 = nh.get(new Coord(2,3)); + n9 = nh.get(n9c); + + // all nodes exist? + assertNotNull(n1); + assertNotNull(n2); + assertNotNull(n3); + assertNotNull(n4); + assertNotNull(n5); + assertNotNull(n8); + assertNotNull(n9); + + // nodes have correct amount of neighbors? + assertEquals(2, n1.getNeighbors().size()); + assertEquals(3, n2.getNeighbors().size()); + assertEquals(1, n3.getNeighbors().size()); + assertEquals(2, n4.getNeighbors().size()); + assertEquals(2, n5.getNeighbors().size()); + assertEquals(2, n8.getNeighbors().size()); + assertEquals(1, n9.getNeighbors().size()); + } + + public void testFromFile() throws IOException { + File wktFile = File.createTempFile("WKTReaderTest","tmp"); + wktFile.deleteOnExit(); + PrintWriter pw = new PrintWriter(wktFile); + WKTMapReader reader; + + pw.println(TST_TOPOLOGY); + pw.close(); + reader = setUpWith(new FileReader(wktFile)); + + basicNodesTests(reader); + topologyTest(reader.getNodesHash()); + } + + public void testMultiLineString() { + String multiline = "MULTILINESTRING ((1.0 1.0, 2.0 1.0, 3.0 1.0),"+ + "(1.0 1.0, 1.0 2.0))"; + StringReader input = new StringReader(multiline); + Map nh; + + WKTMapReader reader = setUpWith(input); + nh = reader.getNodesHash(); + + assertEquals(4, nh.size()); + } + + public void testReadContents() throws IOException { + String c1 = "lorem ipsum dolor sit amet"; + String c2 = "lorem ipsum\r\ndolor sit\n\r amet"; + String internal = "(lorem),(ipsum)"; + String cont = "ACTION ("+c1+")"; + String cont2 = "ACTION ("+c2+")"; + String cont3 = "MLS ("+internal+")"; + + WKTMapReader r = new WKTMapReader(true); + + StringReader s = new StringReader(cont3); + assertEquals(internal, r.readNestedContents(s)); + + s = new StringReader(cont); + assertEquals(c1,r.readNestedContents(s)); + + s = new StringReader(cont2); + // should convert newline to space + c2 = c2.replaceAll("(\r|\n)", " "); + assertEquals(c2,r.readNestedContents(s)); + } + + public void testMapOperations() { + String wkt = "LINESTRING (1.0 1.0, 2.0 5.0)\n" + + "LINESTRING (1.0 1.0, 1.0 3.0)\n"; + WKTMapReader reader = setUpWith(new StringReader(wkt)); + SimMap map = reader.getMap(); + + Coord max = map.getMaxBound(); + Coord min = map.getMinBound(); + + assertEquals(2.0, max.getX()); + assertEquals(5.0, max.getY()); + assertEquals(1.0, min.getX()); + assertEquals(1.0, min.getY()); + + map.translate(-1, -1); + max = map.getMaxBound(); + min = map.getMinBound(); + + assertEquals(1.0, max.getX()); + assertEquals(4.0, max.getY()); + assertEquals(0.0, min.getX()); + assertEquals(0.0, min.getY()); + + } + + public void testMultipleMapFiles() throws Exception { + File wktFile1 = File.createTempFile("WKTReaderTest","tmp"); + File wktFile2 = File.createTempFile("WKTReaderTest","tmp"); + File wktFile3 = File.createTempFile("WKTReaderTest","tmp"); + wktFile1.deleteOnExit(); + wktFile2.deleteOnExit(); + wktFile3.deleteOnExit(); + + PrintWriter pw = new PrintWriter(wktFile1); + pw.println(TST_TOPOLOGY); + pw.close(); + pw = new PrintWriter(wktFile2); + pw.println(ADD_TOPOLOGY); + pw.close(); + pw = new PrintWriter(wktFile3); + pw.println(ADD_TOPOLOGY2); + pw.close(); + + WKTMapReader reader = new WKTMapReader(true); + reader.addPaths(wktFile1, 1); + reader.addPaths(wktFile2, 2); + reader.addPaths(wktFile3, 31); + + basicNodesTests(reader); + + SimMap map = reader.getMap(); + + // n1 should be of type 1 + MapNode n1 = map.getNodeByCoord(n1c); + assertTrue(n1.isType(1)); + assertTrue(n1.isType(new int [] {2,1})); + assertFalse(n1.isType(2)); + + // n10 should be of type 2 + assertTrue(map.getNodeByCoord(n10c).isType(2)); + assertFalse(map.getNodeByCoord(n10c).isType(1)); + + // n9 should be type1, type2 and type31 + MapNode n9 = map.getNodeByCoord(n9c); + assertTrue(n9.isType(2)); + assertTrue(n9.isType(1)); + assertTrue(n9.isType(31)); + assertFalse(n9.isType(4)); + + assertTrue(n9.isType(new int [] {1,2,31})); + assertTrue(n9.isType(new int [] {5,2})); + assertTrue(n9.isType(new int [] {1,5})); + assertTrue(n9.isType(new int [] {5,7,31})); + assertFalse(n9.isType(new int [] {5,7,8})); + + // n11 should be only 31 + assertTrue(map.getNodeByCoord(n11c).isType(31)); + assertFalse(map.getNodeByCoord(n11c).isType(2)); + } + + private void basicNodesTests(WKTMapReader reader) { + Collection col = reader.getNodes(); + + // contains something + assertTrue(col.size() > 0); + + for (MapNode n : col) { + // no lonely nodes + assertTrue(n.getNeighbors().size() >= 1); + } + } + +} diff --git a/test/WorldTest.java b/test/WorldTest.java index f54a9b5eb..a70de35d9 100644 --- a/test/WorldTest.java +++ b/test/WorldTest.java @@ -1,149 +1,149 @@ -/* +/* * Copyright 2010 Aalto University, ComNet - * Released under GPLv3. See LICENSE.txt for details. - */ -package test; - -import input.EventQueue; - -import java.util.ArrayList; -import java.util.List; - -import junit.framework.TestCase; -import core.DTNHost; -import core.ModuleCommunicationBus; -import core.NetworkInterface; -import core.SimClock; -import core.UpdateListener; -import core.World; - - -/** - * Tests for the World class - * TODO: much more tests - */ -public class WorldTest extends TestCase { - /* for rounding errors with SimClock */ - private static final double TIME_DELTA = 0.00001; - private World world; - private boolean simulateConnections = true; - private int worldSizeX = 100; - private int worldSizeY = 100; - private double upInterval = 0.1; - private List testHosts; - private List eQueues; - - protected void setUp() throws Exception { - super.setUp(); - SimClock.reset(); - TestSettings testSettings = new TestSettings(); - testSettings.setNameSpace(TestUtils.IFACE_NS); - testSettings.putSetting(NetworkInterface.TRANSMIT_RANGE_S, "1.0"); - testSettings.putSetting(NetworkInterface.TRANSMIT_SPEED_S, "1"); - - this.eQueues = new ArrayList(); - this.testHosts = new ArrayList(); - for (int i=0; i<10; i++) { - NetworkInterface ni = new TestInterface(testSettings); - List li = new ArrayList(); - li.add(ni); - ModuleCommunicationBus comBus = new ModuleCommunicationBus(); - - this.testHosts.add(new TestDTNHost(li, comBus, testSettings)); - } - - TestScenario ts = new TestScenario(); - this.world = new World(ts.getHosts(),ts.getWorldSizeX(), - ts.getWorldSizeY(),ts.getUpdateInterval(), - ts.getUpdateListeners(), ts.simulateConnections(), - ts.getExternalEvents() ); - } - - public void testUpdate() { - double endTime = 1000; - int nrofRounds = (int)(endTime/upInterval); - - for (int i=0; i getUpdateListeners() { - return new ArrayList(); - } - - public List getHosts() { - ArrayList hs = new ArrayList(); - for (TestDTNHost h : testHosts) { - hs.add(h); - } - return hs; - } - - public boolean simulateConnections() { - return simulateConnections; - } - - public List getExternalEvents() { - return eQueues; - } - - public double getMaxHostRange() { - return 10; - } - - protected void createHosts() { - this.hosts = new ArrayList(); - } - } -} + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import input.EventQueue; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import core.DTNHost; +import core.ModuleCommunicationBus; +import core.NetworkInterface; +import core.SimClock; +import core.UpdateListener; +import core.World; + + +/** + * Tests for the World class + * TODO: much more tests + */ +public class WorldTest extends TestCase { + /* for rounding errors with SimClock */ + private static final double TIME_DELTA = 0.00001; + private World world; + private boolean simulateConnections = true; + private int worldSizeX = 100; + private int worldSizeY = 100; + private double upInterval = 0.1; + private List testHosts; + private List eQueues; + + protected void setUp() throws Exception { + super.setUp(); + SimClock.reset(); + TestSettings testSettings = new TestSettings(); + testSettings.setNameSpace(TestUtils.IFACE_NS); + testSettings.putSetting(NetworkInterface.TRANSMIT_RANGE_S, "1.0"); + testSettings.putSetting(NetworkInterface.TRANSMIT_SPEED_S, "1"); + + this.eQueues = new ArrayList(); + this.testHosts = new ArrayList(); + for (int i=0; i<10; i++) { + NetworkInterface ni = new TestInterface(testSettings); + List li = new ArrayList(); + li.add(ni); + ModuleCommunicationBus comBus = new ModuleCommunicationBus(); + + this.testHosts.add(new TestDTNHost(li, comBus, testSettings)); + } + + TestScenario ts = new TestScenario(); + this.world = new World(ts.getHosts(),ts.getWorldSizeX(), + ts.getWorldSizeY(),ts.getUpdateInterval(), + ts.getUpdateListeners(), ts.simulateConnections(), + ts.getExternalEvents() ); + } + + public void testUpdate() { + double endTime = 1000; + int nrofRounds = (int)(endTime/upInterval); + + for (int i=0; i getUpdateListeners() { + return new ArrayList(); + } + + public List getHosts() { + ArrayList hs = new ArrayList(); + for (TestDTNHost h : testHosts) { + hs.add(h); + } + return hs; + } + + public boolean simulateConnections() { + return simulateConnections; + } + + public List getExternalEvents() { + return eQueues; + } + + public double getMaxHostRange() { + return 10; + } + + protected void createHosts() { + this.hosts = new ArrayList(); + } + } +} diff --git a/test/package.html b/test/package.html index 88f91ece0..7617458a2 100644 --- a/test/package.html +++ b/test/package.html @@ -1,8 +1,8 @@ - - - - -Provides some unit and integration tests for the classes. - - - \ No newline at end of file + + + + +Provides some unit and integration tests for the classes. + + + diff --git a/toolkit/Common.pm b/toolkit/Common.pm index 6a5aa9095..81634faed 100644 --- a/toolkit/Common.pm +++ b/toolkit/Common.pm @@ -35,14 +35,14 @@ Discarded lines and "errors" are printed to stderr. $infile = shift @ARGV;; $outfile = shift @ARGV; - + if ($infile) { open(INFILE, $infile) or die "Can't open $infile : $!"; } else { open(INFILE, "<-") or die "Can't read from stdin"; } - + if ($outfile) { open OUTFILE, ">$outfile" or die "Can't open $outfile : $!"; } diff --git a/toolkit/ccdfPlotter.pl b/toolkit/ccdfPlotter.pl index 423fe128b..032d7a8d2 100755 --- a/toolkit/ccdfPlotter.pl +++ b/toolkit/ccdfPlotter.pl @@ -1,201 +1,201 @@ -#! /usr/bin/perl - -package Toolkit; - -# (C)CDF gnuplot plotter - -use strict; -use warnings; -use Getopt::Long; - -# path to the gnuplot program -my $gnuplot = "gnuplot"; - -my ( - $outfile, $constTotalSum, $hitCountIndex, - $labelRe, $term, $range, - $params, $comp, $logscale, $help -); - -my $usage = ' -usage: -out - [-comp] - [-log] - [-total ] - [-index ] - [-label ] - [-params ] - [-term ] - [-range ] - fileNames... -'; - -GetOptions( - "total=i" => \$constTotalSum, - "index=i" => \$hitCountIndex, - "label=s" => \$labelRe, - "params=s" => \$params, - "out=s" => \$outfile, - "term=s" => \$term, - "range=s" => \$range, - "comp!" => \$comp, - "log!" => \$logscale, - "help|?!" => \$help -); - -if ($help) { - print '(Complementary) Cumulative Distribution plotter. Creates CDF plots -from timestamped hitcount reports using gnuplot. All given input files -are plotted to the same graph.'; - print "\n$usage"; - print ' -options: - -out Output file name\'s prefix - -total If defined, the total value against which cumulative values are compared. - By default, total is calculated from the input file. - -index Index (which of whitespace delimeted fields) of the hitcount value. - Default = 1 (first field after time stamp). Zero value reports hitcount - of 1 for each line. - -comp Do Complementary CDF instead of normal CDF - -label A regular expression which is used to parse labels for plots from the - input file names. Use capture groups to get the content(s). - Default = \'([^_]*)_\' (everything up to the first underscore) - -params Gnuplot plotting style parameters. Default = \'smooth unique\' - -term Name of the terminal used for gnuplot output. Use "na" for no terminal - (only the gnuplot output file is created). Default = emf - -range Range of x-values in the resulting graph (e.g. 0:100). - Default = no range, i.e. automatic scaling by gnuplot -'; - exit(); -} - -if ( not defined $outfile or not @ARGV ) { - print "Missing required parameter(s)\n"; - print $usage; - exit(); -} - -$hitCountIndex = 1 unless defined $hitCountIndex; -$term = "emf" unless defined $term; -$params = "smooth unique" unless defined $params; -$labelRe = '([^_]*)_' unless defined $labelRe; - -my $plotfile = "$outfile.gnuplot"; - -open( PLOT, ">$plotfile" ) or die "Can't open plot output file $plotfile : $!"; -if ($logscale) { - print PLOT "set logscale x\n"; -} -if ($comp) { - print PLOT "set ylabel \"1-P(X <= x)\"\n"; -} -else { - print PLOT "set ylabel \"P(X <= x)\"\n"; -} -if ( defined($range) ) { - print PLOT "set xrange [$range]\n"; -} - -if ( not $term eq "na" ) { - my ($suffix) = $term=~ /(\S+)/; - print PLOT "set terminal $term\n"; - print PLOT "set output \"$outfile.$suffix\"\n"; -} -print PLOT "plot "; - -my $round = 0; -while ( my $infile = shift(@ARGV) ) { - if ( $round > 0 ) { - print PLOT ", "; - } - $round++; - - open( INFILE, "$infile" ) or die "Can't open $infile : $!"; - - # strip 1-3 char extension (if any) - if ( $infile =~ m/.*\.\w{1,3}/ ) { - ($infile) = $infile =~ m/(.*)\.\w{1,3}/; - } - - my $cdffile = "$infile.cdf"; - - my $totalSum; - my $hitcount; - my $time; - my @values; - - open( OUTFILE, ">$cdffile" ) or die "Can't open output file $cdffile : $!"; - - if ( defined $constTotalSum ) { - $totalSum = $constTotalSum; - } - else { - while () { - @values = split; - next if $values[0] eq "#"; # skip comment lines - - if ( $hitCountIndex > 0 ) { - $totalSum += $values[$hitCountIndex]; - } - else { - $totalSum += 1; - } - } - seek( INFILE, 0, 0 ); - } - - my $cumSum = 0; - - while () { - @values = split; - next if $values[0] eq "#"; - - $time = $values[0]; - if ( $hitCountIndex > 0 ) { - $hitcount = $values[$hitCountIndex]; - } - else { - $hitcount = 1; - } - - if ( $hitcount > 0 ) { - $cumSum += $hitcount; - my $finalValue; - if ($comp) { - $finalValue = 1 - ( $cumSum / $totalSum ); - } - else { - $finalValue = ( $cumSum / $totalSum ); - } - print OUTFILE "$time ", $finalValue, "\n"; - } - } - - close(OUTFILE); - close(INFILE); - - print PLOT "'$cdffile'"; - if ( defined($labelRe) ) { # extract label for legend - my @labels = $infile =~ m/$labelRe/; - die "Cant' extract label using \'$labelRe\' from $infile" - unless @labels; - print PLOT " title \"@labels\""; - } - print PLOT " $params"; - -} - -print PLOT "\n"; -close(PLOT); - -if ( not $term eq "na" ) { - system("$gnuplot $plotfile") == 0 or die "Can't run gnuplot: $?"; -} +#! /usr/bin/perl + +package Toolkit; + +# (C)CDF gnuplot plotter + +use strict; +use warnings; +use Getopt::Long; + +# path to the gnuplot program +my $gnuplot = "gnuplot"; + +my ( + $outfile, $constTotalSum, $hitCountIndex, + $labelRe, $term, $range, + $params, $comp, $logscale, $help +); + +my $usage = ' +usage: -out + [-comp] + [-log] + [-total ] + [-index ] + [-label ] + [-params ] + [-term ] + [-range ] + fileNames... +'; + +GetOptions( + "total=i" => \$constTotalSum, + "index=i" => \$hitCountIndex, + "label=s" => \$labelRe, + "params=s" => \$params, + "out=s" => \$outfile, + "term=s" => \$term, + "range=s" => \$range, + "comp!" => \$comp, + "log!" => \$logscale, + "help|?!" => \$help +); + +if ($help) { + print '(Complementary) Cumulative Distribution plotter. Creates CDF plots +from timestamped hitcount reports using gnuplot. All given input files +are plotted to the same graph.'; + print "\n$usage"; + print ' +options: + +out Output file name\'s prefix + +total If defined, the total value against which cumulative values are compared. + By default, total is calculated from the input file. + +index Index (which of whitespace delimeted fields) of the hitcount value. + Default = 1 (first field after time stamp). Zero value reports hitcount + of 1 for each line. + +comp Do Complementary CDF instead of normal CDF + +label A regular expression which is used to parse labels for plots from the + input file names. Use capture groups to get the content(s). + Default = \'([^_]*)_\' (everything up to the first underscore) + +params Gnuplot plotting style parameters. Default = \'smooth unique\' + +term Name of the terminal used for gnuplot output. Use "na" for no terminal + (only the gnuplot output file is created). Default = emf + +range Range of x-values in the resulting graph (e.g. 0:100). + Default = no range, i.e. automatic scaling by gnuplot +'; + exit(); +} + +if ( not defined $outfile or not @ARGV ) { + print "Missing required parameter(s)\n"; + print $usage; + exit(); +} + +$hitCountIndex = 1 unless defined $hitCountIndex; +$term = "emf" unless defined $term; +$params = "smooth unique" unless defined $params; +$labelRe = '([^_]*)_' unless defined $labelRe; + +my $plotfile = "$outfile.gnuplot"; + +open( PLOT, ">$plotfile" ) or die "Can't open plot output file $plotfile : $!"; +if ($logscale) { + print PLOT "set logscale x\n"; +} +if ($comp) { + print PLOT "set ylabel \"1-P(X <= x)\"\n"; +} +else { + print PLOT "set ylabel \"P(X <= x)\"\n"; +} +if ( defined($range) ) { + print PLOT "set xrange [$range]\n"; +} + +if ( not $term eq "na" ) { + my ($suffix) = $term=~ /(\S+)/; + print PLOT "set terminal $term\n"; + print PLOT "set output \"$outfile.$suffix\"\n"; +} +print PLOT "plot "; + +my $round = 0; +while ( my $infile = shift(@ARGV) ) { + if ( $round > 0 ) { + print PLOT ", "; + } + $round++; + + open( INFILE, "$infile" ) or die "Can't open $infile : $!"; + + # strip 1-3 char extension (if any) + if ( $infile =~ m/.*\.\w{1,3}/ ) { + ($infile) = $infile =~ m/(.*)\.\w{1,3}/; + } + + my $cdffile = "$infile.cdf"; + + my $totalSum; + my $hitcount; + my $time; + my @values; + + open( OUTFILE, ">$cdffile" ) or die "Can't open output file $cdffile : $!"; + + if ( defined $constTotalSum ) { + $totalSum = $constTotalSum; + } + else { + while () { + @values = split; + next if $values[0] eq "#"; # skip comment lines + + if ( $hitCountIndex > 0 ) { + $totalSum += $values[$hitCountIndex]; + } + else { + $totalSum += 1; + } + } + seek( INFILE, 0, 0 ); + } + + my $cumSum = 0; + + while () { + @values = split; + next if $values[0] eq "#"; + + $time = $values[0]; + if ( $hitCountIndex > 0 ) { + $hitcount = $values[$hitCountIndex]; + } + else { + $hitcount = 1; + } + + if ( $hitcount > 0 ) { + $cumSum += $hitcount; + my $finalValue; + if ($comp) { + $finalValue = 1 - ( $cumSum / $totalSum ); + } + else { + $finalValue = ( $cumSum / $totalSum ); + } + print OUTFILE "$time ", $finalValue, "\n"; + } + } + + close(OUTFILE); + close(INFILE); + + print PLOT "'$cdffile'"; + if ( defined($labelRe) ) { # extract label for legend + my @labels = $infile =~ m/$labelRe/; + die "Cant' extract label using \'$labelRe\' from $infile" + unless @labels; + print PLOT " title \"@labels\""; + } + print PLOT " $params"; + +} + +print PLOT "\n"; +close(PLOT); + +if ( not $term eq "na" ) { + system("$gnuplot $plotfile") == 0 or die "Can't run gnuplot: $?"; +} diff --git a/toolkit/createCircles.pl b/toolkit/createCircles.pl index a4c6963b0..1000e8c3f 100755 --- a/toolkit/createCircles.pl +++ b/toolkit/createCircles.pl @@ -13,11 +13,11 @@ package Toolkit; # number of rings my ($rings, $radius, $help); - + GetOptions("rings=n" => \$rings, "radius=n" => \$radius, "help|?!" => \$help); - + unless (defined($help)) { unless (defined($rings) and defined($radius)) { print "Missing required parameters\n"; @@ -56,5 +56,5 @@ package Toolkit; $hostID++; } } - + } diff --git a/toolkit/createCreates.pl b/toolkit/createCreates.pl index dc1bca5cb..8464e31aa 100755 --- a/toolkit/createCreates.pl +++ b/toolkit/createCreates.pl @@ -19,14 +19,14 @@ package Toolkit; my $msgIndex = 1; my ($randSeed, $nrofMessages, $times, $hosts, $sizes, $rsizes, $help); - -GetOptions("seed=i" => \$randSeed, "time=s" => \$times, - "nrof=i" => \$nrofMessages, - "hosts=s" => \$hosts, + +GetOptions("seed=i" => \$randSeed, "time=s" => \$times, + "nrof=i" => \$nrofMessages, + "hosts=s" => \$hosts, "sizes=s" => \$sizes, "rsizes=s" => \$rsizes, "help|?!" => \$help); - + unless (defined($help)) { unless (defined($times) and defined($nrofMessages) and defined($hosts) and defined($sizes)) { @@ -65,7 +65,7 @@ package Toolkit; for (my $time = $start; $time < $end; $time += $step) { my $prob = $step * (($nrofMessages - $nrof) / ($end - $time)); - + if (rand() < $prob) { my $from = int(rand() * ($maxHost-$minHost) + $minHost); my $to = $from; @@ -73,7 +73,7 @@ package Toolkit; $to = int(rand() * ($maxHost-$minHost) + $minHost); } my $size = int(rand() * ($maxSize-$minSize) + $minSize); - + printf "%.${prec}f",$time; print "\tC\t$msgPrefix$msgIndex\t$hostPrefix$from\t$hostPrefix$to"; print "\t$size"; diff --git a/toolkit/delProb.pl b/toolkit/delProb.pl index d48a5f771..410c1500e 100755 --- a/toolkit/delProb.pl +++ b/toolkit/delProb.pl @@ -35,13 +35,13 @@ package Toolkit; while () { if (m/^#/) { next; # skip comment lines - } - + } + my ($dist, $time) = m/^([\d\.-]+) ([\d\.-]+)/; die "invalid input line $_" unless defined $dist; my $index = int($dist / $granularity); # map distance values to table indexes - + if ($time == -1) { $nrofNotDelivered[$index] = 0 unless defined $nrofNotDelivered[$index]; $nrofNotDelivered[$index]++; @@ -60,7 +60,7 @@ package Toolkit; my $del = $nrofDelivered[$i]; my $nDel = $nrofNotDelivered[$i]; my $delProb; - + if (not defined($del) and not defined($nDel)) { next; # skip distance slots that don't have any data } @@ -73,9 +73,9 @@ package Toolkit; else { $delProb = $del / ($del + $nDel); } - + my $dist = $granularity * ($i+1); - + print OUTFILE "$dist $delProb\n"; } diff --git a/toolkit/dieselnetConverter.pl b/toolkit/dieselnetConverter.pl index 2d005c525..877309910 100644 --- a/toolkit/dieselnetConverter.pl +++ b/toolkit/dieselnetConverter.pl @@ -1,126 +1,126 @@ -#! /usr/local/bin/perl - -# UMass Dieselnet -> the ONE trace converter -# Suitable (at least) for "DieselNet Fall 2007" from -# http://traces.cs.umass.edu/index.php/Network/Network - -package Toolkit; -use strict; -use warnings; -use FileHandle; -use Getopt::Long; - -my $usage = ' -usage: -out [-help] [-first ] - -'; - -my ($help, $outFileName, $first); - -GetOptions("out=s"=>\$outFileName, "first=i"=>\$first, "help|?!" => \$help); - -$first = -1 unless defined $first; # no adjustment by default - -if (not $help and (not $outFileName or not @ARGV)) { - print "Missing required parameter(s)\n"; - print $usage; - exit(); -} - -if ($help) { - print 'Dieselnet trace converter.'; - print "\n$usage"; - print ' -options: -out Name of the output file - -first Time stamp for the first connection event. Adjusts all timestamps so - that the first event happens at this time (by N seconds from the start - of the simulation). By default, the times are not adjusted at all. -'; - exit(); -} - -# Input example: -# PVTA_3201 PVTA_3117 0:16:14 235560.0 584.0 42.38768 -72.52352 - -# Output example: -# 974 CONN 12 7 up -# 1558 CONN 12 7 down - -my $inputFile = shift @ARGV; -my $inFh = new FileHandle; -my $outFh = new FileHandle; -$inFh->open("<$inputFile") or die "Can't open input file $inputFile"; -$outFh->open(">$outFileName") or die "Can't create outputfile $outFileName"; - -print $outFh "# Connection trace file for the ONE. Converted from $inputFile \n"; - -my @lines = <$inFh>; # read whole file to array -my @output; -my $nextNodeId = 0; -my ($nodeId1, $nodeId2, %nodeIds); - -foreach (@lines) { - if (m/^\s$/) { - next; # skip empty lines - } - - my ($node1, $node2, $h, $m, $s, $duration) = - m/(\w+) (\w+) (\d+):(\d+):(\d+) [\d\.E]+ (\d+\.\d+)/; - die "Invalid input line: $_" unless ($node1 and $node2); - my $time = $h * 3600 + $m * 60 + $s; - - # map node IDs consistently to network addresses - if (exists $nodeIds{$node1}) { - $nodeId1 = $nodeIds{$node1}; - } - else { - $nodeId1 = $nextNodeId; - $nodeIds{$node1} = $nextNodeId; - $nextNodeId++; - } - if (exists $nodeIds{$node2}) { - $nodeId2 = $nodeIds{$node2}; - } - else { - $nodeId2 = $nextNodeId; - $nodeIds{$node2} = $nextNodeId; - $nextNodeId++; - } - - my $conEndTime = $time + $duration; - push(@output, "$time CONN $nodeId1 $nodeId2 up"); - push(@output, "$conEndTime CONN $nodeId1 $nodeId2 down"); -} - -# sort result by time stamp -@output = sort -{ - my ($t1) = $a =~ m/^(\d+)/; - my ($t2) = $b =~ m/^(\d+)/; - $t1 <=> $t2; -} @output; - -# adjust time stamps (if requested with cmd line option) -if ($first != -1) { - my ($firstTime) = $output[0] =~ m/^(\d+)/; - my $diff = $firstTime - $first; - print "Adjusting timestamps by $diff seconds\n"; - foreach (@output) { - my ($ts) = m/^(\d+)/; - my $newTime = $ts - $diff; - s/$ts/$newTime/; - } -} - -# print all the result lines to output file -print $outFh join("\n", @output); - -print "Node name to network ID mapping:\n"; -while (my ($k,$v) = each %nodeIds ) { - print "$k => $v\n"; -} - -$outFh->close(); -$inFh->close(); \ No newline at end of file +#! /usr/local/bin/perl + +# UMass Dieselnet -> the ONE trace converter +# Suitable (at least) for "DieselNet Fall 2007" from +# http://traces.cs.umass.edu/index.php/Network/Network + +package Toolkit; +use strict; +use warnings; +use FileHandle; +use Getopt::Long; + +my $usage = ' +usage: -out [-help] [-first ] + +'; + +my ($help, $outFileName, $first); + +GetOptions("out=s"=>\$outFileName, "first=i"=>\$first, "help|?!" => \$help); + +$first = -1 unless defined $first; # no adjustment by default + +if (not $help and (not $outFileName or not @ARGV)) { + print "Missing required parameter(s)\n"; + print $usage; + exit(); +} + +if ($help) { + print 'Dieselnet trace converter.'; + print "\n$usage"; + print ' +options: +out Name of the output file + +first Time stamp for the first connection event. Adjusts all timestamps so + that the first event happens at this time (by N seconds from the start + of the simulation). By default, the times are not adjusted at all. +'; + exit(); +} + +# Input example: +# PVTA_3201 PVTA_3117 0:16:14 235560.0 584.0 42.38768 -72.52352 + +# Output example: +# 974 CONN 12 7 up +# 1558 CONN 12 7 down + +my $inputFile = shift @ARGV; +my $inFh = new FileHandle; +my $outFh = new FileHandle; +$inFh->open("<$inputFile") or die "Can't open input file $inputFile"; +$outFh->open(">$outFileName") or die "Can't create outputfile $outFileName"; + +print $outFh "# Connection trace file for the ONE. Converted from $inputFile \n"; + +my @lines = <$inFh>; # read whole file to array +my @output; +my $nextNodeId = 0; +my ($nodeId1, $nodeId2, %nodeIds); + +foreach (@lines) { + if (m/^\s$/) { + next; # skip empty lines + } + + my ($node1, $node2, $h, $m, $s, $duration) = + m/(\w+) (\w+) (\d+):(\d+):(\d+) [\d\.E]+ (\d+\.\d+)/; + die "Invalid input line: $_" unless ($node1 and $node2); + my $time = $h * 3600 + $m * 60 + $s; + + # map node IDs consistently to network addresses + if (exists $nodeIds{$node1}) { + $nodeId1 = $nodeIds{$node1}; + } + else { + $nodeId1 = $nextNodeId; + $nodeIds{$node1} = $nextNodeId; + $nextNodeId++; + } + if (exists $nodeIds{$node2}) { + $nodeId2 = $nodeIds{$node2}; + } + else { + $nodeId2 = $nextNodeId; + $nodeIds{$node2} = $nextNodeId; + $nextNodeId++; + } + + my $conEndTime = $time + $duration; + push(@output, "$time CONN $nodeId1 $nodeId2 up"); + push(@output, "$conEndTime CONN $nodeId1 $nodeId2 down"); +} + +# sort result by time stamp +@output = sort +{ + my ($t1) = $a =~ m/^(\d+)/; + my ($t2) = $b =~ m/^(\d+)/; + $t1 <=> $t2; +} @output; + +# adjust time stamps (if requested with cmd line option) +if ($first != -1) { + my ($firstTime) = $output[0] =~ m/^(\d+)/; + my $diff = $firstTime - $first; + print "Adjusting timestamps by $diff seconds\n"; + foreach (@output) { + my ($ts) = m/^(\d+)/; + my $newTime = $ts - $diff; + s/$ts/$newTime/; + } +} + +# print all the result lines to output file +print $outFh join("\n", @output); + +print "Node name to network ID mapping:\n"; +while (my ($k,$v) = each %nodeIds ) { + print "$k => $v\n"; +} + +$outFh->close(); +$inFh->close(); diff --git a/toolkit/dtnsim2parser.pl b/toolkit/dtnsim2parser.pl index 21f0456f6..653726edc 100755 --- a/toolkit/dtnsim2parser.pl +++ b/toolkit/dtnsim2parser.pl @@ -12,7 +12,7 @@ package Toolkit; # epidemic simulations. use strict; -use warnings; +use warnings; use Common; # parseArgs and debug methods parseArgs("dtnsim2parser"); @@ -36,19 +36,19 @@ package Toolkit; ); while() { - # timestamp action msgId + # timestamp action msgId my ($time, $action, $id) = m/^(\d+\.\d+): ([\w\s]+):? (MSG_\d+_D_\d+)_\(\d+\)/; - + unless ($time and $action and $id) { debug ("Discarded: $_"); next; } - + my $actionCode = $commandMapping{$action}; die "Unknown action '" , $action,"'\n" unless $actionCode or $ignoreCommands{$action}; next unless $actionCode; - + my $lastPart; if ($actionCode eq 'C') { @@ -73,7 +73,7 @@ package Toolkit; die "Couldn't parse contact from $_\n" unless $h1 and $h2; $lastPart = "$h1\t$h2"; } - + print OUTFILE "$time\t$actionCode\t$id\t$lastPart\n"; - + } diff --git a/toolkit/getAverages.pl b/toolkit/getAverages.pl index ad8cf226c..a0890c7c4 100644 --- a/toolkit/getAverages.pl +++ b/toolkit/getAverages.pl @@ -24,14 +24,14 @@ package Toolkit; } if ($help) { - print 'Report file value averager. Counts and prints out average for -each line over multiple files. + print 'Report file value averager. Counts and prints out average for +each line over multiple files. Expected syntax for input files: