Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
peersimgrid release 1.0
authorkbaati <kbaati@realopt-Latitude-E6530>
Fri, 24 Jul 2015 10:24:03 +0000 (12:24 +0200)
committerkbaati <kbaati@realopt-Latitude-E6530>
Fri, 24 Jul 2015 10:24:03 +0000 (12:24 +0200)
190 files changed:
contrib/psg/README.txt [new file with mode: 0644]
contrib/psg/configs/bittorrent.txt [new file with mode: 0644]
contrib/psg/configs/bittorrentPSG.txt [new file with mode: 0644]
contrib/psg/configs/chord.txt [new file with mode: 0644]
contrib/psg/configs/chordPSG.txt [new file with mode: 0644]
contrib/psg/configs/edaggregation.txt [new file with mode: 0644]
contrib/psg/configs/edaggregationPSG.txt [new file with mode: 0644]
contrib/psg/configs/symphony.txt [new file with mode: 0644]
contrib/psg/configs/symphonyPSG.txt [new file with mode: 0644]
contrib/psg/lib.jar [new file with mode: 0644]
contrib/psg/platforms/psg.xml [new file with mode: 0644]
contrib/psg/run.sh [new file with mode: 0755]
contrib/psg/src/example/bittorrent/BTObserver.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/BitTorrent.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/BitfieldMsg.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/IntMsg.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/NetworkDynamics.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/NetworkInitializer.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/NodeInitializer.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/PeerSetMsg.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/SimpleEvent.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/SimpleMsg.java [new file with mode: 0644]
contrib/psg/src/example/chord/ChordInitializer.java [new file with mode: 0644]
contrib/psg/src/example/chord/ChordMessage.java [new file with mode: 0644]
contrib/psg/src/example/chord/ChordProtocol.java [new file with mode: 0644]
contrib/psg/src/example/chord/CreateNw.java [new file with mode: 0644]
contrib/psg/src/example/chord/FinalMessage.java [new file with mode: 0644]
contrib/psg/src/example/chord/LookUpMessage.java [new file with mode: 0644]
contrib/psg/src/example/chord/MessageCounterObserver.java [new file with mode: 0644]
contrib/psg/src/example/chord/NodeComparator.java [new file with mode: 0644]
contrib/psg/src/example/chord/Parameters.java [new file with mode: 0644]
contrib/psg/src/example/chord/TrafficGenerator.java [new file with mode: 0644]
contrib/psg/src/example/edaggregation/AverageED.java [new file with mode: 0644]
contrib/psg/src/example/symphony/AdapterIterableNetwork.java [new file with mode: 0644]
contrib/psg/src/example/symphony/AdapterSymphonyNodeComparator.java [new file with mode: 0644]
contrib/psg/src/example/symphony/Handler.java [new file with mode: 0644]
contrib/psg/src/example/symphony/LeaveTest.java [new file with mode: 0644]
contrib/psg/src/example/symphony/Message.java [new file with mode: 0644]
contrib/psg/src/example/symphony/NetworkSizeEstimatorProtocolInterface.java [new file with mode: 0644]
contrib/psg/src/example/symphony/RandomRouteTest.java [new file with mode: 0644]
contrib/psg/src/example/symphony/RingRouteTest.java [new file with mode: 0644]
contrib/psg/src/example/symphony/RoutingException.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SimpleNetworkSizeEstimatorProtocol.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyEstimationProtocol.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyNetworkBuilder.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyNetworkChecker.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyNetworkManager.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyNodeComparator.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyNodeInizializer.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyProtocol.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyStatistics.java [new file with mode: 0644]
contrib/psg/src/example/symphony/Tuple.java [new file with mode: 0644]
contrib/psg/src/example/symphony/test/NetworkEstimationTest.java [new file with mode: 0644]
contrib/psg/src/peersim/Simulator.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/CDProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/CDSimulator.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/CDState.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/DaemonProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/FullNextCycle.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/NextCycle.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/Shuffle.java [new file with mode: 0644]
contrib/psg/src/peersim/config/CheckConfig.java [new file with mode: 0644]
contrib/psg/src/peersim/config/ClassFinder.java [new file with mode: 0644]
contrib/psg/src/peersim/config/ConfigContainer.java [new file with mode: 0644]
contrib/psg/src/peersim/config/ConfigProperties.java [new file with mode: 0644]
contrib/psg/src/peersim/config/Configuration.java [new file with mode: 0644]
contrib/psg/src/peersim/config/FastConfig.java [new file with mode: 0644]
contrib/psg/src/peersim/config/IllegalParameterException.java [new file with mode: 0644]
contrib/psg/src/peersim/config/MissingParameterException.java [new file with mode: 0644]
contrib/psg/src/peersim/config/NullPrintStream.java [new file with mode: 0644]
contrib/psg/src/peersim/config/Operators.java [new file with mode: 0644]
contrib/psg/src/peersim/config/ParsedProperties.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Cleanable.java [new file with mode: 0644]
contrib/psg/src/peersim/core/CommonState.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Control.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Fallible.java [new file with mode: 0644]
contrib/psg/src/peersim/core/GeneralNode.java [new file with mode: 0644]
contrib/psg/src/peersim/core/IdleProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Linkable.java [new file with mode: 0644]
contrib/psg/src/peersim/core/MaliciousProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/core/ModifiableNode.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Network.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Node.java [new file with mode: 0644]
contrib/psg/src/peersim/core/OracleIdleProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/core/OverlayGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Protocol.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Scheduler.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/DynamicNetwork.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/MethodInvoker.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/NodeInitializer.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/OscillatingNetwork.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/RandNI.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/StarNI.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireByMethod.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireFromFile.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireKOut.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireRegRootedTree.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireRingLattice.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireScaleFreeBA.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireScaleFreeDM.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireStar.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireWS.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/CDScheduler.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/ControlEvent.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/EDProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/EDSimulator.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/Heap.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/NextCycleEvent.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/PriorityQ.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/RandNextCycle.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/RegRandNextCycle.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/edsim_jsp.xmi [new file with mode: 0644]
contrib/psg/src/peersim/edsim/edsim_kdm.xmi [new file with mode: 0644]
contrib/psg/src/peersim/graph/BitMatrixGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/ConstUndirGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/FastUndirGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/Graph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/GraphAlgorithms.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/GraphFactory.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/GraphIO.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/NeighbourListGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/PrefixSubGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/SubGraphEdges.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/UndirectedGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/rangesim/ProcessHandler.java [new file with mode: 0644]
contrib/psg/src/peersim/rangesim/ProcessManager.java [new file with mode: 0644]
contrib/psg/src/peersim/rangesim/RangeSimulator.java [new file with mode: 0644]
contrib/psg/src/peersim/rangesim/TaggedOutputStream.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/BallExpansion.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/Clustering.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/ConnectivityObserver.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/DegreeStats.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/GraphObserver.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/GraphPrinter.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/GraphStats.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/MemoryObserver.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/RandRemoval.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/E2ENetwork.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/E2ETransport.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/KingParser.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/RouterInfo.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/Transport.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/TriangularMatrixParser.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/UniformRandomTransport.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/UniformRouterAssignment.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/UnreliableTransport.java [new file with mode: 0644]
contrib/psg/src/peersim/util/ExtendedRandom.java [new file with mode: 0644]
contrib/psg/src/peersim/util/FileNameGenerator.java [new file with mode: 0644]
contrib/psg/src/peersim/util/IncrementalFreq.java [new file with mode: 0644]
contrib/psg/src/peersim/util/IncrementalStats.java [new file with mode: 0644]
contrib/psg/src/peersim/util/IndexIterator.java [new file with mode: 0644]
contrib/psg/src/peersim/util/LinearIterator.java [new file with mode: 0644]
contrib/psg/src/peersim/util/MedianStats.java [new file with mode: 0644]
contrib/psg/src/peersim/util/MomentStats.java [new file with mode: 0644]
contrib/psg/src/peersim/util/RandPermutation.java [new file with mode: 0644]
contrib/psg/src/peersim/util/StringListParser.java [new file with mode: 0644]
contrib/psg/src/peersim/util/WeightedRandPerm.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/Getter.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/GetterSetterFinder.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/InitVectFromFile.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/LinearDistribution.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/Normalizer.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/PeakDistribution.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/Setter.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/SingleValue.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/SingleValueComparator.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/SingleValueHolder.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/SingleValueObserver.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/TestVectors.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/UniformDistribution.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/ValueDumper.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/VectAngle.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/VectControl.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/VectCopy.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/VectorComparator.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/VectorObserver.java [new file with mode: 0644]
contrib/psg/src/psgsim/NodeHost.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGDynamicNetwork.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGPlatform.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGProcessController.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGProcessCycle.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGProcessEvent.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGProcessLauncher.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGSimulator.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGTask.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGTransport.java [new file with mode: 0644]
contrib/psg/src/psgsim/Sizable.java [new file with mode: 0644]
contrib/psg/test.sh [new file with mode: 0755]
contrib/psg/tutorial.pdf [new file with mode: 0644]

diff --git a/contrib/psg/README.txt b/contrib/psg/README.txt
new file mode 100644 (file)
index 0000000..4435990
--- /dev/null
@@ -0,0 +1,48 @@
+Mon Jan 26 16:00 CEST 2015
+This is version 1.0 of PeerSimGrid
+
+1) An overview
+2) Preliminaries
+3) Compile & Run 
+
+--------------------------------------------------------------------------------------------
+1) An overview:
+PeerSimGrid (PSG) is an interface developed in Java and allows users to simulate 
+and execute their code under PeerSim or Simgrid simulator, using PeerSim implementation policy.
+       
+This archive is composed of:
+* the src/ directory containing the simulator source and examples
+* the configs/ directory containing example of configuration files
+* psg.jar, a java archive containing all libraries  
+
+
+2) Preliminaries:
+       Before using psg simulator, you need to make some changes in your configuration file:
+               * Replace the "UniformRandomTransport" transport protocol by "psgsim.PSGTransport".
+               * Replace the "simulation.endtime" by "simulation.duration"
+               * you can define your platform on the configuration file as:
+                       platform path/to/your/file.xml 
+       
+       
+3) Compile & Run:
+       In short, the way to compile and execute your code is: 
+               Compile it:                
+               $> make compile
+               
+               Test it (optional):
+               $> make test
+               This test execute two examples, (chord and edaggregation found in the example folder), under the two simulators
+               and compare their outputs.      
+               
+               Run it:
+               $> ./run.sh path/to/your/configuration_file 
+               For example: 
+                       $>./run.sh configs/chordPSG.txt 
+                       
+               For the documentation
+               $> make doc
+               
+               For the help command
+               $> make help
+               
+Note: For more informations please contact khaled.baati@gmail.com
\ No newline at end of file
diff --git a/contrib/psg/configs/bittorrent.txt b/contrib/psg/configs/bittorrent.txt
new file mode 100644 (file)
index 0000000..356b302
--- /dev/null
@@ -0,0 +1,46 @@
+#Config file for BitTorrent extension
+
+random.seed 1234567890
+simulation.endtime 1800000#6^8
+simulation.logtime 10^3
+OutputName bittorrent
+simulation.experiments 1
+
+network.size 30
+network.node peersim.core.GeneralNode
+
+protocol.urt UniformRandomTransport
+protocol.urt.mindelay 10
+protocol.urt.maxdelay 400
+
+#BE AWARE: the value "max_swarm_size" must be greater than
+#the value "peerset_size", since I have to be sure
+#that the space for the neighbor nodes is enough.
+
+protocol.bittorrent example.bittorrent.BitTorrent
+protocol.bittorrent.file_size 100
+protocol.bittorrent.max_swarm_size 80
+protocol.bittorrent.peerset_size 50
+protocol.bittorrent.duplicated_requests 1
+protocol.bittorrent.transport urt
+protocol.bittorrent.max_growth 20
+
+init.net example.bittorrent.NetworkInitializer
+init.net.protocol bittorrent
+init.net.transport urt
+init.net.newer_distr 80
+init.net.seeder_distr 15
+
+control.observer example.bittorrent.BTObserver
+control.observer.protocol bittorrent
+control.observer.step 10000
+
+control.dynamics example.bittorrent.NetworkDynamics
+control.dynamics.protocol bittorrent
+control.dynamics.newer_distr 60
+control.dynamics.minsize 20
+control.dynamics.tracker_can_die 1
+control.dynamics.step 100000
+control.dynamics.transport urt
+control.dynamics.add 0#5
+control.dynamics.remove 0#5
\ No newline at end of file
diff --git a/contrib/psg/configs/bittorrentPSG.txt b/contrib/psg/configs/bittorrentPSG.txt
new file mode 100644 (file)
index 0000000..647ccb4
--- /dev/null
@@ -0,0 +1,48 @@
+#Config file for BitTorrent extension
+OutputName bittorrent
+platform platforms/psg.xml
+unit ms
+random.seed 1234567890
+simulation.duration 1800000
+simulation.logtime 10^3
+
+simulation.experiments 1
+
+network.size 40
+network.node peersim.core.GeneralNode
+
+protocol.urt psgsim.PSGTransport
+protocol.urt.mindelay 0#10
+protocol.urt.maxdelay 0#400
+
+#BE AWARE: the value "max_swarm_size" must be greater than
+#the value "peerset_size", since I have to be sure
+#that the space for the neighbor nodes is enough.
+
+protocol.bittorrent example.bittorrent.BitTorrent
+protocol.bittorrent.file_size 100
+protocol.bittorrent.max_swarm_size 80
+protocol.bittorrent.peerset_size 50
+protocol.bittorrent.duplicated_requests 1
+protocol.bittorrent.transport urt
+protocol.bittorrent.max_growth 20
+
+init.net example.bittorrent.NetworkInitializer
+init.net.protocol bittorrent
+init.net.transport urt
+init.net.newer_distr 80
+init.net.seeder_distr 15
+
+control.observer example.bittorrent.BTObserver
+control.observer.protocol bittorrent
+control.observer.step 10000
+
+control.dynamics example.bittorrent.NetworkDynamics
+control.dynamics.protocol bittorrent
+control.dynamics.newer_distr 60
+control.dynamics.minsize 20
+control.dynamics.tracker_can_die 1
+control.dynamics.step 100000
+control.dynamics.transport urt
+control.dynamics.add 0#5
+control.dynamics.remove 0#5
\ No newline at end of file
diff --git a/contrib/psg/configs/chord.txt b/contrib/psg/configs/chord.txt
new file mode 100644 (file)
index 0000000..deeee8f
--- /dev/null
@@ -0,0 +1,51 @@
+# PEERSIM CHORD\r
+\r
+random.seed 1234567890\r
+simulation.endtime 10^4\r
+simulation.logtime 10^6\r
+OutputName chord\r
+simulation.experiments 1\r
+\r
+network.size 40\r
+protocol.tr UniformRandomTransport\r
+{\r
+       mindelay 0\r
+       maxdelay 0\r
+}\r
+\r
+protocol.chord  example.chord.ChordProtocol\r
+{\r
+       transport tr\r
+}\r
+\r
+control.traffic example.chord.TrafficGenerator\r
+{\r
+       protocol chord\r
+       step 100\r
+}\r
+\r
+init.create example.chord.CreateNw \r
+{\r
+       protocol chord\r
+       idLength 128\r
+       succListSize 12\r
+}\r
+\r
+control.observer example.chord.MessageCounterObserver\r
+{\r
+       protocol chord\r
+       step 90000\r
+}\r
+\r
+#control.dnet DynamicNetwork\r
+#{\r
+#      #add 2\r
+#      add -2\r
+#      minsize 18#3000\r
+#      maxsize 60#7000\r
+#      step 100000\r
+#      init.0 example.chord.ChordInitializer\r
+#      {      \r
+#              protocol chord\r
+#      }\r
+#}
\ No newline at end of file
diff --git a/contrib/psg/configs/chordPSG.txt b/contrib/psg/configs/chordPSG.txt
new file mode 100644 (file)
index 0000000..7e67047
--- /dev/null
@@ -0,0 +1,54 @@
+# PEERSIM CHORD\r
+\r
+random.seed 1234567890\r
+simulation.duration 10^4\r
+simulation.logtime 10^6\r
+unit sec\r
+OutputName chord\r
+platform platforms/psg.xml\r
+simulation.experiments 1\r
+\r
+network.size 40\r
+protocol.tr psgsim.PSGTransport\r
+{\r
+       mindelay 0\r
+       maxdelay 0\r
+}\r
+\r
+protocol.chord  example.chord.ChordProtocol\r
+{\r
+       transport tr\r
+}\r
+\r
+control.traffic example.chord.TrafficGenerator\r
+{\r
+       protocol chord\r
+       step 100\r
+}\r
+\r
+init.create example.chord.CreateNw \r
+{\r
+       protocol chord\r
+       idLength 128\r
+       succListSize 12\r
+}\r
+\r
+control.observer example.chord.MessageCounterObserver\r
+{\r
+       protocol chord\r
+       step 90000\r
+}\r
+\r
+\r
+#control.dnet DynamicNetwork\r
+#{\r
+#      #add 2\r
+#      add -2\r
+#      minsize 18#3000\r
+#      maxsize 60#7000\r
+#      step 100000\r
+#      init.0 example.chord.ChordInitializer\r
+#      {      \r
+#              protocol chord\r
+#      }\r
+#}\r
diff --git a/contrib/psg/configs/edaggregation.txt b/contrib/psg/configs/edaggregation.txt
new file mode 100644 (file)
index 0000000..d3aec12
--- /dev/null
@@ -0,0 +1,57 @@
+# network size
+SIZE 50
+OutputName edaggregation
+
+# parameters of periodic execution
+CYCLES 100
+CYCLE SIZE*100
+
+# parameters of message transfer
+# delay values here are relative to cycle length, in percentage,
+# eg 50 means half the cycle length, 200 twice the cycle length, etc.
+MINDELAY 0
+MAXDELAY 0
+# drop is a probability, 0<=DROP<=1
+DROP 0
+
+random.seed 1234567890
+network.size SIZE
+simulation.endtime CYCLE*CYCLES
+simulation.logtime CYCLE
+
+################### protocols ===========================
+
+protocol.link peersim.core.IdleProtocol
+
+protocol.avg example.edaggregation.AverageED
+protocol.avg.linkable link
+protocol.avg.step CYCLE
+protocol.avg.transport tr
+
+protocol.tr UnreliableTransport
+protocol.tr.transport urt
+protocol.tr.drop DROP
+
+protocol.urt UniformRandomTransport
+protocol.urt.mindelay (CYCLE*MINDELAY)/100
+protocol.urt.maxdelay (CYCLE*MAXDELAY)/100
+################### initialization ======================
+
+init.rndlink WireKOut
+init.rndlink.k 20
+init.rndlink.protocol link
+
+init.vals LinearDistribution
+init.vals.protocol avg
+init.vals.max SIZE
+init.vals.min 1
+
+init.sch CDScheduler
+init.sch.protocol avg
+init.sch.randstart
+
+################ control ==============================
+
+control.0 SingleValueObserver
+control.0.protocol avg
+control.0.step CYCLE
diff --git a/contrib/psg/configs/edaggregationPSG.txt b/contrib/psg/configs/edaggregationPSG.txt
new file mode 100644 (file)
index 0000000..8510e90
--- /dev/null
@@ -0,0 +1,57 @@
+# network size
+SIZE 50
+OutputName edaggregation
+platform platforms/psg.xml
+unit sec
+# parameters of periodic execution
+CYCLES 100
+CYCLE SIZE*100
+# parameters of message transfer
+# delay values here are relative to cycle length, in percentage,
+# eg 50 means half the cycle length, 200 twice the cycle length, etc.
+MINDELAY 0
+MAXDELAY 0
+# drop is a probability, 0<=DROP<=1
+DROP 0
+
+random.seed 1234567890
+network.size SIZE
+simulation.duration CYCLE*CYCLES
+simulation.logtime CYCLE
+
+################### protocols ===========================
+
+protocol.link peersim.core.IdleProtocol
+
+protocol.avg example.edaggregation.AverageED
+protocol.avg.linkable link
+protocol.avg.step CYCLE
+protocol.avg.transport tr
+
+protocol.tr UnreliableTransport
+protocol.tr.transport urt
+protocol.tr.drop DROP
+
+protocol.urt psgsim.PSGTransport
+protocol.urt.mindelay (CYCLE*MINDELAY)/100
+protocol.urt.maxdelay (CYCLE*MAXDELAY)/100
+################### initialization ======================
+
+init.rndlink WireKOut
+init.rndlink.k 20
+init.rndlink.protocol link
+
+init.vals LinearDistribution
+init.vals.protocol avg
+init.vals.max SIZE
+init.vals.min 1
+
+init.sch CDScheduler
+init.sch.protocol avg
+init.sch.randstart
+
+################ control ==============================
+
+control.0 SingleValueObserver
+control.0.protocol avg
+control.0.step CYCLE
diff --git a/contrib/psg/configs/symphony.txt b/contrib/psg/configs/symphony.txt
new file mode 100644 (file)
index 0000000..fb5c778
--- /dev/null
@@ -0,0 +1,154 @@
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::\r
+# :: Symphony Default Configuration\r
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::\r
+\r
+# network size\r
+SIZE 50\r
+\r
+# parameters of periodic execution\r
+CYCLES 100\r
+CYCLE SIZE/2\r
+OutputName symphony\r
+\r
+# parameters of message transfer\r
+# delay values here are relative to cycle length, in percentage,\r
+# eg 50 means half the cycle length, 200 twice the cycle length, etc.\r
+MINDELAY 0\r
+MAXDELAY 0\r
+\r
+random.seed 1234567890\r
+network.size SIZE\r
+simulation.experiments 1\r
+simulation.endtime 2000#CYCLE*CYCLES\r
+simulation.logtime CYCLE\r
+\r
+################### transports ===========================\r
+\r
+protocol.tr UniformRandomTransport \r
+{\r
+       mindelay (CYCLE*MINDELAY)/100\r
+       maxdelay (CYCLE*MAXDELAY)/100\r
+}\r
+\r
+################### protocols ===========================\r
+\r
+order.protocol link networkestimator symphony symphonynetworkmanager\r
+\r
+protocol.link peersim.core.IdleProtocol\r
+\r
+protocol.symphony example.symphony.SymphonyProtocol\r
+{\r
+       linkable link\r
+       transport tr\r
+       shortlink 4\r
+       # if commented means: longlink log(n)\r
+       #longlink 4\r
+       routing unidirectional\r
+       lookahead off\r
+}\r
+\r
+#protocol.networkestimator example.symphony.SimpleNetworkSizeEstimatorProtocol\r
+\r
+protocol.networkestimator example.symphony.SymphonyEstimationProtocol\r
+{\r
+       symphony symphony\r
+       # if commented means: s log(n)\r
+       #s 3\r
+}\r
+\r
+protocol.symphonynetworkmanager example.symphony.SymphonyNetworkManager\r
+{\r
+       symphony symphony\r
+       transport tr\r
+       networkestimator networkestimator\r
+       attempts 3\r
+       nTimeout 5\r
+       relinking on\r
+       relinkingLowerBound 0.5\r
+       relinkingUpperBound 2.0\r
+       step 4*CYCLE #useless\r
+}\r
+\r
+################### initialization ======================\r
+\r
+order.init netbuild checknet\r
+\r
+init.netbuild example.symphony.SymphonyNetworkBuilder\r
+{\r
+       symphony symphony\r
+       createLongLinks true\r
+       attempts 5\r
+}\r
+\r
+init.checknet example.symphony.SymphonyNetworkChecker\r
+{\r
+       symphony symphony\r
+       networkestimator networkestimator\r
+}\r
+\r
+################ control ==============================\r
+\r
+order.control sch checknet randomroutetest ringroutetest leavetest dnet estimationtest statistics\r
+\r
+control.randomroutetest example.symphony.RandomRouteTest\r
+{\r
+       symphony symphony\r
+       step CYCLE\r
+}\r
+\r
+control.ringroutetest example.symphony.RingRouteTest\r
+{\r
+       symphony symphony\r
+       startnode 0\r
+       step CYCLE\r
+}\r
+\r
+control.sch CDScheduler\r
+{\r
+       protocol symphonynetworkmanager\r
+       step CYCLE*2\r
+       randstart\r
+}\r
+\r
+control.checknet example.symphony.SymphonyNetworkChecker\r
+{\r
+       symphony symphony\r
+       networkestimator networkestimator\r
+       step CYCLE\r
+}\r
+\r
+control.dnet peersim.dynamics.DynamicNetwork\r
+{\r
+       add 0\r
+       maxsize 50\r
+       minsize SIZE/2\r
+       step CYCLE*2\r
+       init.0 example.symphony.SymphonyNodeInizializer\r
+       {\r
+               symphonynetworkmanager symphonynetworkmanager\r
+               symphony symphony\r
+               bootstrapnode 0\r
+       }\r
+}\r
+\r
+control.leavetest example.symphony.LeaveTest\r
+{\r
+       symphonynetworkmanager symphonynetworkmanager\r
+       n 1\r
+       minsizeOnline SIZE-1\r
+       waitTargetSizeToStart 2*SIZE\r
+       step CYCLE*2\r
+}\r
+\r
+control.statistics example.symphony.SymphonyStatistics\r
+{\r
+       symphony symphony\r
+       step (CYCLE*CYCLES)-1\r
+}\r
+\r
+control.estimationtest example.symphony.test.NetworkEstimationTest\r
+{\r
+       symphony symphony\r
+       symphonynetworkmanager symphonynetworkmanager\r
+       step CYCLE*4\r
+}
\ No newline at end of file
diff --git a/contrib/psg/configs/symphonyPSG.txt b/contrib/psg/configs/symphonyPSG.txt
new file mode 100644 (file)
index 0000000..20b7dce
--- /dev/null
@@ -0,0 +1,155 @@
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::\r
+# :: Symphony Default Configuration\r
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::\r
+\r
+# network size\r
+SIZE 50\r
+unit sec\r
+# parameters of periodic execution\r
+CYCLES 100\r
+CYCLE SIZE/2\r
+OutputName symphony\r
+platform platforms/psg.xml\r
+\r
+# parameters of message transfer\r
+# delay values here are relative to cycle length, in percentage,\r
+# eg 50 means half the cycle length, 200 twice the cycle length, etc.\r
+MINDELAY 0\r
+MAXDELAY 0\r
+\r
+random.seed 1234567890\r
+network.size SIZE\r
+simulation.experiments 1\r
+simulation.duration 2000#CYCLE*CYCLES\r
+simulation.logtime CYCLE\r
+\r
+################### transports ===========================\r
+\r
+protocol.tr psgsim.PSGTransport \r
+{\r
+       mindelay (CYCLE*MINDELAY)/100\r
+       maxdelay (CYCLE*MAXDELAY)/100\r
+}\r
+\r
+################### protocols ===========================\r
+\r
+order.protocol link networkestimator symphony symphonynetworkmanager\r
+\r
+protocol.link peersim.core.IdleProtocol\r
+\r
+protocol.symphony example.symphony.SymphonyProtocol\r
+{\r
+       linkable link\r
+       transport tr\r
+       shortlink 4\r
+       # if commented means: longlink log(n)\r
+       #longlink 4\r
+       routing unidirectional\r
+       lookahead off\r
+}\r
+\r
+#protocol.networkestimator example.symphony.SimpleNetworkSizeEstimatorProtocol\r
+\r
+protocol.networkestimator example.symphony.SymphonyEstimationProtocol\r
+{\r
+       symphony symphony\r
+       # if commented means: s log(n)\r
+       #s 3\r
+}\r
+\r
+protocol.symphonynetworkmanager example.symphony.SymphonyNetworkManager\r
+{\r
+       symphony symphony\r
+       transport tr\r
+       networkestimator networkestimator\r
+       attempts 3\r
+       nTimeout 5\r
+       relinking on\r
+       relinkingLowerBound 0.5\r
+       relinkingUpperBound 2.0\r
+       step 4*CYCLE #useless\r
+}\r
+\r
+################### initialization ======================\r
+\r
+order.init netbuild checknet\r
+\r
+init.netbuild example.symphony.SymphonyNetworkBuilder\r
+{\r
+       symphony symphony\r
+       createLongLinks true\r
+       attempts 5\r
+}\r
+\r
+init.checknet example.symphony.SymphonyNetworkChecker\r
+{\r
+       symphony symphony\r
+       networkestimator networkestimator\r
+}\r
+\r
+################ control ==============================\r
+\r
+order.control sch checknet randomroutetest ringroutetest leavetest dnet estimationtest statistics\r
+\r
+control.randomroutetest example.symphony.RandomRouteTest\r
+{\r
+       symphony symphony\r
+       step CYCLE\r
+}\r
+\r
+control.ringroutetest example.symphony.RingRouteTest\r
+{\r
+       symphony symphony\r
+       startnode 0\r
+       step CYCLE\r
+}\r
+\r
+control.sch CDScheduler\r
+{\r
+       protocol symphonynetworkmanager\r
+       step CYCLE*2\r
+       randstart\r
+}\r
+\r
+control.checknet example.symphony.SymphonyNetworkChecker\r
+{\r
+       symphony symphony\r
+       networkestimator networkestimator\r
+       step CYCLE\r
+}\r
+\r
+control.dnet peersim.dynamics.DynamicNetwork\r
+{\r
+       add 0\r
+       maxsize 50\r
+       minsize SIZE/2\r
+       step CYCLE*2\r
+       init.0 example.symphony.SymphonyNodeInizializer\r
+       {\r
+               symphonynetworkmanager symphonynetworkmanager\r
+               symphony symphony\r
+               bootstrapnode 0\r
+       }\r
+}\r
+\r
+control.leavetest example.symphony.LeaveTest\r
+{\r
+       symphonynetworkmanager symphonynetworkmanager\r
+       n 1\r
+       minsizeOnline SIZE-1\r
+       waitTargetSizeToStart 2*SIZE\r
+       step CYCLE*2\r
+}\r
+\r
+control.statistics example.symphony.SymphonyStatistics\r
+{\r
+       symphony symphony\r
+       step (CYCLE*CYCLES)-1\r
+}\r
+\r
+control.estimationtest example.symphony.test.NetworkEstimationTest\r
+{\r
+       symphony symphony\r
+       symphonynetworkmanager symphonynetworkmanager\r
+       step CYCLE*4\r
+}\r
diff --git a/contrib/psg/lib.jar b/contrib/psg/lib.jar
new file mode 100644 (file)
index 0000000..8fd65fa
Binary files /dev/null and b/contrib/psg/lib.jar differ
diff --git a/contrib/psg/platforms/psg.xml b/contrib/psg/platforms/psg.xml
new file mode 100644 (file)
index 0000000..bdd2e19
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version='1.0'?>
+<!DOCTYPE platform SYSTEM "http://simgrid.gforge.inria.fr/simgrid.dtd">
+<!--             _________
+                |          |
+                |  router  |
+    ____________|__________|_____________ backbone
+      |   |   |              |     |   |       
+    l0|        l1| l2|           l97| l96 |   | l99
+      |   |   |   ........   |     |   |
+      |                                |
+    c-0.me                             c-99.me 
+
+-->
+<platform version="3">
+<config>
+<prop id="network/latency_factor" value="1.0"/>
+</config>
+<AS  id="AS0"  routing="Full">
+  <cluster id="my_cluster_1" prefix="" suffix=""
+               radical="0-50000"       power="1Gf"  bw="200Mbps" lat="0ms"
+        bb_bw="200Mbps" bb_lat="0ms"/>
+</AS>
+</platform>
diff --git a/contrib/psg/run.sh b/contrib/psg/run.sh
new file mode 100755 (executable)
index 0000000..ecac88c
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+if [ $(uname -m) = "i686" ]; then
+       eval ulimit -s 64
+else 
+       eval ulimit -s 128
+fi
+echo '------------- Start execution..';
+java -Xmx1024m -cp lib.jar:classes peersim.Simulator $1
+echo '------------- done -------------';
+exit 0
+
+
+
+
diff --git a/contrib/psg/src/example/bittorrent/BTObserver.java b/contrib/psg/src/example/bittorrent/BTObserver.java
new file mode 100644 (file)
index 0000000..ddd38da
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --
+ *
+ * Please send your questions/suggestions to:
+ * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it
+ *
+ */
+
+package example.bittorrent;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * This {@link Control} provides a way to keep track of some
+ * parameters of the BitTorrent network.
+ */
+ public class BTObserver implements Control {
+        
+       /**
+        *      The protocol to operate on.
+        *      @config
+        */
+       private static final String PAR_PROT="protocol";
+       
+       /**
+        *      Protocol identifier, obtained from config property
+        */
+       private final int pid;
+       
+       /**
+        *      The basic constructor that reads the configuration file.
+        *      @param prefix the configuration prefix for this class
+        */
+       public BTObserver(String prefix) {
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);
+       }
+       
+       /**
+        * Prints information about the BitTorrent network
+        * and the number of leechers and seeders.
+        * Please refer to the code comments for more details.
+        * @return always false
+        */
+       public boolean execute() {
+               IncrementalFreq nodeStatusStats = new IncrementalFreq();
+               IncrementalStats neighborStats = new IncrementalStats();
+               
+               int numberOfNodes = Network.size();
+               int numberOfCompletedPieces = 0;
+               
+               // cycles from 1, since the node 0 is the tracker
+               for (int i=1; i<numberOfNodes; ++i) {
+                       
+                       // stats on number of leechers and seeders in the network
+                       // and consequently also on number of completed files in the network
+                       nodeStatusStats.add(((BitTorrent)(Network.get(i).getProtocol(pid))).getPeerStatus());
+                       
+                       // stats on number of neighbors per peer
+                       neighborStats.add(((BitTorrent)(Network.get(i).getProtocol(pid))).getNNodes());
+               }
+               
+               // number of the pieces of the file, equal for every node, here 1 is chosen,
+               // since 1 is the first "normal" node (0 is the tracker)
+               int numberOfPieces = ((BitTorrent)(Network.get(1).getProtocol(pid))).nPieces;
+       
+               for (int i=1; i<numberOfNodes; ++i) {
+                       numberOfCompletedPieces = 0;
+                       
+                       // discovers the status of the current peer (leecher or seeder)
+                       int ps = ((BitTorrent)(Network.get(i).getProtocol(pid))).getPeerStatus();
+                       String peerStatus;
+                       if (ps==0) {
+                               peerStatus = "L"; //leecher
+                       }
+                       else {
+                               peerStatus = "S"; //seeder
+                       }
+                       
+                       
+                       if (Network.get(i)!=null) {
+                               
+                               // counts the number of completed pieces for the i-th node
+                               for (int j=0; j<numberOfPieces; j++) {
+                                       if ( ((BitTorrent)(Network.get(i).getProtocol(pid))).getFileStatus()[j] == 16) {
+                                               numberOfCompletedPieces++;
+                                       }
+                               }
+                               
+                               /*
+                                * Put here the output lines of the Observer. An example is provided with
+                                * basic information and stats.
+                                * CommonState.getTime() is used to print out time references
+                                * (useful for graph plotting).
+                                */
+                               
+                               System.out.println("OBS: node " + ((BitTorrent)(Network.get(i).getProtocol(pid))).getThisNodeID() + "(" + peerStatus + ")" + "\t pieces completed: " + numberOfCompletedPieces + "\t \t down: " + ((BitTorrent)(Network.get(i).getProtocol(pid))).nPiecesDown + "\t up: " + ((BitTorrent)(Network.get(i).getProtocol(pid))).nPiecesUp + " time: " + CommonState.getTime());
+                               //System.out.println("[OBS] t " + CommonState.getTime() + "\t pc " + numberOfCompletedPieces + "\t n " + ((BitTorrent)(Network.get(i).getProtocol(pid))).getThisNodeID());
+                               //System.out.println( CommonState.getTime() + "\t" + numberOfCompletedPieces + "\t" + ((BitTorrent)(Network.get(i).getProtocol(pid))).getThisNodeID());
+
+                       }
+                       else {
+                               //System.out.println("[OBS] t " + CommonState.getTime() + "\t pc " + "0" + "\t n " + "0");
+                       }
+               
+               }
+               
+               // prints the frequency of 0 (leechers) and 1 (seeders)
+               nodeStatusStats.printAll(System.out);
+               
+               // prints the average number of neighbors per peer
+               System.out.println("Avg number of neighbors per peer: " + neighborStats.getAverage());
+               
+               return false;
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/bittorrent/BitTorrent.java b/contrib/psg/src/example/bittorrent/BitTorrent.java
new file mode 100644 (file)
index 0000000..1604a4d
--- /dev/null
@@ -0,0 +1,1989 @@
+/*
+ * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --
+ *
+ * Please send your questions/suggestions to:
+ * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it
+ *
+ */
+
+package example.bittorrent;
+
+import peersim.core.*;
+import peersim.config.*;
+import peersim.edsim.*;
+import peersim.transport.*;
+
+/**
+ *     This is the class that implements the BitTorrent module for Peersim
+ */
+public class BitTorrent implements EDProtocol {
+       /**
+        *      The size in Megabytes of the file being shared.
+        *      @config
+        */
+       private static final String PAR_SIZE="file_size";
+       /**
+        *      The Transport used by the the protocol.
+        *      @config
+        */
+       private static final String PAR_TRANSPORT="transport";
+       /**
+        *      The maximum number of neighbor that a node can have. 
+        *      @config
+        */
+       private static final String PAR_SWARM="max_swarm_size";
+       /**
+        *      The maximum number of peers returned by the tracker when a new
+        *      set of peers is requested through a <tt>TRACKER</tt> message.
+        *      @config
+        */
+       private static final String PAR_PEERSET_SIZE="peerset_size";
+       /**
+        *      Defines how much the network can grow with respect to the <tt>network.size</tt> 
+        *  when {@link NetworkDynamics} is used.
+        *      @config
+        */
+       private static final String PAR_MAX_GROWTH="max_growth";
+       /**
+        *      Is the number of requests of the same block sent to different peers.
+        *      @config
+        */
+       private static final String PAR_DUP_REQ = "duplicated_requests";
+       
+       /**
+        *      KEEP_ALIVE message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int KEEP_ALIVE = 1;
+       
+       /**
+        *      CHOKE message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int CHOKE = 2;
+       
+       /**
+        *      UNCHOKE message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int UNCHOKE = 3;
+       
+       /**
+        *      INTERESTED message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int INTERESTED = 4;
+       
+       /**
+        *      NOT_INTERESTED message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int NOT_INTERESTED = 5;
+       
+       /**
+        *      HAVE message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int HAVE = 6;
+       
+       /**
+        *      BITFIELD message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int BITFIELD = 7;
+       
+       /**
+        *      REQUEST message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int REQUEST = 8;
+       
+       /**
+        *      PIECE message.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int PIECE = 9;
+
+       /**
+        *      CANCEL message.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int CANCEL = 10;
+       
+       /**
+        *      TRACKER message.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int TRACKER = 11;
+       
+       /**
+        *      PEERSET message.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int PEERSET = 12;
+       
+       /**
+        *      CHOKE_TIME event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int CHOKE_TIME = 13;
+       
+       /**
+        *      OPTUNCHK_TIME event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int OPTUNCHK_TIME = 14;
+       
+       /**
+        *      ANTISNUB_TIME event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int ANTISNUB_TIME = 15;
+       
+       /**
+        *      CHECKALIVE_TIME event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int CHECKALIVE_TIME = 16;
+       
+       /**
+        *      TRACKERALIVE_TIME event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int TRACKERALIVE_TIME = 17;
+       
+       /**
+        *      DOWNLOAD_COMPLETED event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int DOWNLOAD_COMPLETED = 18;
+
+       /**
+        *      The maxium connection speed of the local node.
+        */
+       int maxBandwidth;
+       
+       /**
+        *      Stores the neighbors ordered by ID.
+        *  @see Element
+        */
+       private example.bittorrent.Element byPeer[];
+       
+       /**
+        *      Contains the neighbors ordered by bandwidth as needed by the unchocking
+        *      algorithm.
+        */
+       private example.bittorrent.Element byBandwidth[];
+       
+       /**
+        *      The Neighbors list.
+        */
+       private Neighbor cache[];
+       
+       /**
+        *      Reference to the neighbors that unchocked the local node.
+        */
+       private boolean unchokedBy[];
+       
+       /**
+        *      Number of neighbors in the cache. When it decreases under 20, a new peerset
+        *      is requested to the tracker.
+        */
+       private int nNodes = 0;
+       
+       /**
+        *      Maximum number of nodes in the network.
+        */
+       private int nMaxNodes;
+       
+       /**
+        *      The status of the local peer. 0 means that the current peer is a leecher, 1 a seeder.
+        */ 
+       private int peerStatus;
+       
+       /**
+        *      Defines how much the network can grow with respect to the <tt>network.size</tt> 
+        *  when {@link NetworkDynamics} is used.
+        */
+       public int maxGrowth;
+       
+       /**
+        *      File status of the local node. Contains the blocks owned by the local node.
+        */
+       private int status[];
+       
+       /**
+        *      Current number of Bitfield request sent. It must be taken into account 
+        *      before sending another one.
+        */
+       private int nBitfieldSent = 0;
+       
+       /**
+        *      Current number of pieces in upload from the local peer.
+        */
+       public int nPiecesUp = 0;
+       /**
+        *      Current number of pieces in download to the local peer.
+        */
+       public int nPiecesDown = 0;
+       
+       /**
+        *      Current number of piece completed.
+        */
+       private int nPieceCompleted = 0;
+       
+       /**
+        *      Current downloading piece ID, the previous lastInterested piece.
+        */
+       int currentPiece = -1;
+       
+       /**
+        *      Used to compute the average download rates in choking algorithm. Stores the
+        *      number of <tt>CHOKE</tt> events.
+        */
+       int n_choke_time = 0;
+       
+       /**
+        *      Used to send the <tt>TRACKER</tt> message when the local node has 20 neighbors
+        *      for the first time.
+        */
+       boolean lock = false;
+       
+       /**
+        *      Number of peers interested to my pieces.
+        */
+       int numInterestedPeers = 0;
+       
+       /**
+        *      Last piece for which the local node sent an <tt>INTERESTED</tt> message.
+        */
+       int lastInterested = -1;
+       
+       /** 
+        *      The status of the current piece in download. Length 16, every time the local node
+        *      receives a PIECE message, it updates the corrisponding block's cell. The cell
+        *      contains the ID for that block of that piece. If an already owned
+        *      block is received this is discarded.
+        */
+       private int pieceStatus[];
+       
+       /**     
+        *      Length of the file. Stored as number of pieces (256KB each one).
+        */
+       int nPieces;
+       
+       /**
+        *      Contains the neighbors's status of the file. Every row represents a
+        *      node and every a cell has value O if the neighbor doesn't 
+        *      have the piece, 1 otherwise. It has {@link #swarmSize} rows and {@link #nPieces}
+        *      columns.
+        */
+       int [][]swarm;
+       
+       /**     
+        *      The summation of the swarm's rows. Calculated every time a {@link #BITFIELD} message
+        *      is received and updated every time HAVE message is received.
+        */
+       int rarestPieceSet[];
+       
+       /**
+        *      The five pending block requests.
+        */
+       int pendingRequest[];
+       
+       /**
+        *      The maximum swarm size (default is 80)
+        */
+       int swarmSize;
+       
+       /**
+        *      The size of the peerset. This is the number of "friends" nodes
+        *      sent from the tracker to each new node (default: 50)
+        */
+       int peersetSize;
+       
+       /**
+        * The ID of the current node
+        */
+       private long thisNodeID;
+       
+       /**
+     * Number of duplicated requests as specified in the configuration file.
+        *      @see BitTorrent#PAR_DUP_REQ
+        */
+       private int numberOfDuplicatedRequests;
+       
+       /**
+        *      The queue where the requests to serve are stored.
+        *      The default dimension of the queue is 20.
+        */
+       Queue requestToServe = null;
+       
+       /**
+        *      The queue where the out of sequence incoming pieces are stored
+        *      waiting for the right moment to be processed.
+     * The default dimension of the queue is 100.
+        */
+       Queue incomingPieces = null;
+       
+       /**
+        *      The Transport ID.
+        *      @see BitTorrent#PAR_TRANSPORT
+        */
+       int tid;
+       
+       /**
+        *      The reference to the tracker node. If equals to <tt>null</tt>, the local
+        *      node is the tracker.
+        */
+       private Node tracker = null;
+       
+       /**
+        *      The default constructor. Reads the configuration file and initializes the
+        *      configuration parameters.
+        *      @param prefix the component prefix declared in the configuration file
+        */
+       public BitTorrent(String prefix){ // Used for the tracker's protocol
+               tid = Configuration.getPid(prefix+"."+PAR_TRANSPORT);
+               nPieces = (int)((Configuration.getInt(prefix+"."+PAR_SIZE))*1000000/256000);
+               swarmSize = (int)Configuration.getInt(prefix+"."+PAR_SWARM);
+               peersetSize = (int)Configuration.getInt(prefix+"."+PAR_PEERSET_SIZE);
+               numberOfDuplicatedRequests = (int)Configuration.getInt(prefix+"."+PAR_DUP_REQ);
+               maxGrowth = (int)Configuration.getInt(prefix+"."+PAR_MAX_GROWTH);
+               nMaxNodes = Network.getCapacity()-1;
+       }
+       
+       /**
+        *      Gets the reference to the tracker node.
+        *      @return the reference to the tracker
+        */
+       public Node getTracker(){
+               return tracker;
+       }
+       
+       /**
+        *      Gets the number of neighbors currently stored in the cache of the local node.
+        *      @return the number of neighbors in the cache
+        */
+       public int getNNodes(){
+               return this.nNodes;
+       }
+       
+       /**
+        *      Sets the reference to the tracker node.
+        *      @param t the tracker node
+        */
+       public void setTracker(Node t){
+               tracker = t;
+       }
+       
+       /**
+        *      Sets the ID of the local node.
+        *      @param id the ID of the node
+        */
+       public void setThisNodeID(long id) {
+               this.thisNodeID = id;
+       }
+       
+       /**
+        *      Gets the ID of the local node.
+        *      @return the ID of the local node
+        */
+       public long getThisNodeID(){
+               return this.thisNodeID;
+       }
+       
+       /**
+        *      Gets the file status of the local node.
+        *      @return the file status of the local node
+        */
+       public int[] getFileStatus(){
+               return this.status;
+       }
+       
+       /**
+        *      Initializes the tracker node. This method
+        *      only performs the initialization of the tracker's cache.
+        */
+       public void initializeTracker() {
+               cache = new Neighbor[nMaxNodes+maxGrowth];
+               for(int i=0; i<nMaxNodes+maxGrowth; i++){
+                       cache[i]= new Neighbor();
+               }
+       }
+       
+       /**
+        *      <p>Checks the number of neighbors and if it is equal to 20
+        *      sends a TRACKER messages to the tracker, asking for a new
+        *      peer set.</p>
+        *
+        *      <p>This method *must* be called after every call of {@link #removeNeighbor}
+        *      in {@link #processEvent}.
+        *      </p>
+        */
+       private void processNeighborListSize(Node node, int pid) {
+               if (nNodes==20) {
+                       Object ev;
+                       long latency;
+                       ev = new SimpleMsg(TRACKER, node);
+                       Node tracker = ((BitTorrent)node.getProtocol(pid)).tracker;
+                       if(tracker != null){
+//                             latency = ((Transport)node.getProtocol(tid)).getLatency(node, tracker);
+//                             EDSimulator.add(latency,ev,tracker,pid);
+                               ((Transport) node.getProtocol(tid)).send(node, tracker, ev, pid);
+                       }
+               }
+       }
+       
+       /**
+        *      The standard method that processes incoming events.
+        *      @param node reference to the local node for which the event is going to be processed
+        *      @param pid BitTorrent's protocol id
+        *      @param event the event to process
+        */
+       public void processEvent(Node node, int pid, Object event){
+               
+               Object ev;
+               long latency;
+               switch(((SimpleEvent)event).getType()){
+                       
+                       case KEEP_ALIVE: // 1
+                       {
+                               Node sender = ((IntMsg)event).getSender();
+                               int isResponse = ((IntMsg)event).getInt();
+                               //System.out.println("process, keep_alive: sender is "+sender.getID()+", local is "+node.getID());
+                               Element e = search(sender.getID());
+                               if(e!= null){ //if I know the sender
+                                       cache[e.peer].isAlive();
+                                       if(isResponse==0 && alive(sender)){
+                                               Object msg = new IntMsg(KEEP_ALIVE,node,1,0);
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node, sender);
+//                                             EDSimulator.add(latency,msg,sender,pid);
+                                               ((Transport) node.getProtocol(tid)).send(node, sender, msg, pid);
+                                               cache[e.peer].justSent();
+                                       }
+                               }
+                               else{
+                                       System.err.println("despite it should never happen, it happened");
+                                       ev = new BitfieldMsg(BITFIELD, true, false, node, status, nPieces);
+//                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                     EDSimulator.add(latency,ev,sender,pid);                                 
+                                       ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                       nBitfieldSent++;
+                               }
+                               
+                       };break;
+                               
+                       case CHOKE: // 2, CHOKE message.
+                       {
+                               Node sender = ((SimpleMsg)event).getSender();
+                               //System.out.println("process, choke: sender is "+sender.getID()+", local is "+node.getID());
+                               Element e = search(sender.getID());
+                               if(e!= null){ //if I know the sender
+                                       cache[e.peer].isAlive();
+                                       unchokedBy[e.peer]= false; // I'm choked by it
+                               }
+                               else{
+                                       System.err.println("despite it should never happen, it happened");
+                                       ev = new BitfieldMsg(BITFIELD, true, false, node, status, nPieces);
+//                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                     EDSimulator.add(latency,ev,sender,pid);
+                                       ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                       nBitfieldSent++;
+                               }
+                       };break;
+                               
+                       case UNCHOKE: // 3, UNCHOKE message.
+                       {                       
+                               Node sender = ((SimpleMsg)event).getSender();
+                               //System.out.println("process, unchoke: sender is "+sender.getID()+", local is "+node.getID());
+                               Element e = search(sender.getID());
+                               if(e != null){ // If I know the sender
+                                       int senderIndex = e.peer;
+                                       cache[senderIndex].isAlive();
+                                       /* I send to it some of the pending requests not yet satisfied. */
+                                       int t = numberOfDuplicatedRequests;
+                                       for(int i=4;i>=0 && t>0;i--){
+                                               if(pendingRequest[i]==-1)
+                                                       break;
+                                               if(alive(cache[senderIndex].node) && swarm[senderIndex][decode(pendingRequest[i],0)]==1){ //If the sender has that piece
+                                                       ev = new IntMsg(REQUEST, node,pendingRequest[i],0);
+//                                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                                     EDSimulator.add(latency,ev, sender,pid);
+                                                       ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                                       cache[senderIndex].justSent();
+                                               }
+                                               if(!alive(cache[senderIndex].node)){
+                                                       System.out.println("unchoke1 rm neigh "+ cache[i].node.getID() );
+                                                       removeNeighbor(cache[senderIndex].node);
+                                                       processNeighborListSize(node,pid);
+                                                       return;
+                                               }
+                                               t--;
+                                       }
+                                       // I request missing blocks to fill the queue
+                                       int block = getBlock();
+                                       int piece;
+                                       while(block != -2){ //while still available request to send
+                                               if(block < 0){ // No more block to request for the current piece 
+                                                       piece = getPiece();
+                                                       if(piece == -1){ // no more piece to request
+                                                               break;
+                                                       }
+                                                       for(int j=0; j<swarmSize; j++){// send the interested message to those  
+                                                                                                       // nodes which have that piece
+                                                               lastInterested = piece;
+                                                               if(alive(cache[j].node) && swarm[j][piece]==1){                                                                 
+                                                                       ev = new IntMsg(INTERESTED, node, lastInterested,0);
+//                                                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[j].node);
+//                                                                     EDSimulator.add(latency,ev,cache[j].node,pid);  
+                                                                       ((Transport) node.getProtocol(tid)).send(node, cache[j].node, ev, pid);
+                                                                       cache[j].justSent();
+                                                               }
+                                                               
+                                                               if(!alive(cache[j].node)){
+                                                                       //System.out.println("unchoke2 rm neigh "+ cache[j].node.getID() );
+                                                                       removeNeighbor(cache[j].node);
+                                                                       processNeighborListSize(node,pid);
+                                                               }
+                                                       }
+                                                       block = getBlock();
+                                               }
+                                               else{ // block value referred to a real block
+                                                       if(alive(cache[senderIndex].node) && swarm[senderIndex][decode(block,0)]==1 && addRequest(block)){ // The sender has that block
+                                                               ev = new IntMsg(REQUEST, node, block,0);
+//                                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                                             EDSimulator.add(latency,ev,sender,pid);
+                                                               ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+
+                                                               cache[senderIndex].justSent();
+                                                       }
+                                                       else{
+                                                               if(!alive(cache[senderIndex].node)){
+                                                                       System.out.println("unchoke3 rm neigh "+ cache[senderIndex].node.getID() );
+                                                                       removeNeighbor(cache[senderIndex].node);
+                                                                       processNeighborListSize(node,pid);
+                                                               }
+                                                               return;
+                                                       }
+                                                       block = getBlock();
+                                               }
+                                       }
+                                       unchokedBy[senderIndex] = true; // I add the sender to the list
+                               }
+                               else // It should never happen.
+                               {
+                                       System.err.println("despite it should never happen, it happened");
+                                       for(int i=0; i<swarmSize; i++)
+                                               if(cache[i].node !=null)
+                                                       System.err.println(cache[i].node.getID());
+                                       ev = new BitfieldMsg(BITFIELD, true, false, node, status, nPieces);
+//                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                     EDSimulator.add(latency,ev,sender,pid);
+                                       ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                       nBitfieldSent++;
+                               }
+                       };break;
+                               
+                       case INTERESTED: // 4, INTERESTED message.
+                       {
+                               numInterestedPeers++;
+                               Node sender = ((IntMsg)event).getSender();
+                               //System.out.println("process, interested: sender is "+sender.getID()+", local is "+node.getID());
+                               int value = ((IntMsg)event).getInt();
+                               Element e = search(sender.getID());
+                               if(e!=null){
+                                       cache[e.peer].isAlive();
+                                       cache[e.peer].interested = value;
+                               }
+                               else{
+                                       System.err.println("despite it should never happen, it happened");
+                                       ev = new BitfieldMsg(BITFIELD, true, false, node, status, nPieces);
+//                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                     EDSimulator.add(latency,ev,sender,pid);
+                                       ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                       nBitfieldSent++;
+                               }
+                               
+                       }; break;
+                               
+                       case NOT_INTERESTED: // 5, NOT_INTERESTED message.
+                       {
+                               numInterestedPeers--;
+                               Node sender = ((IntMsg)event).getSender();
+                               //System.out.println("process, not_interested: sender is "+sender.getID()+", local is "+node.getID());
+                               int value = ((IntMsg)event).getInt();
+                               Element e = search(sender.getID());
+                               if(e!=null){
+                                       cache[e.peer].isAlive();
+                                       if(cache[e.peer].interested == value)
+                                               cache[e.peer].interested = -1; // not interested
+                               }
+                       }; break;
+                               
+                       case HAVE: // 6, HAVE message.
+                       {               
+                               Node sender = ((IntMsg)event).getSender();
+                               //System.out.println("process, have: sender is "+sender.getID()+", local is "+node.getID());
+                               int piece = ((IntMsg)event).getInt();
+                               Element e = search(sender.getID());
+                               if(e!=null){
+                                       cache[e.peer].isAlive();
+                                       swarm[e.peer][piece]=1;
+                                       rarestPieceSet[piece]++;
+                                       boolean isSeeder = true;
+                                       for(int i=0; i<nPieces; i++){
+                                               isSeeder = isSeeder && (swarm[e.peer][i]==1);   
+                                       }
+                                       e.isSeeder = isSeeder;
+                               }
+                               else{
+                                       System.err.println("despite it should never happen, it happened");
+                                       ev = new BitfieldMsg(BITFIELD, true, false, node, status, nPieces);
+//                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                     EDSimulator.add(latency,ev,sender,pid);
+                                       ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                       nBitfieldSent++;
+                               }
+                       }; break;
+                               
+                       case BITFIELD: // 7, BITFIELD message
+                       {                       
+                               Node sender = ((BitfieldMsg)event).getSender();
+                               int []fileStatus = ((BitfieldMsg)event).getArray();
+                               /*Response with NACK*/
+                               if(!((BitfieldMsg)event).isRequest && !((BitfieldMsg)event).ack){
+                                       Element e = search(sender.getID());
+                                       if(e == null) // if is a response with nack that follows a request
+                                               nBitfieldSent--;
+                                       // otherwise is a response with ack that follows a duplicate
+                                       // insertion attempt
+                                       //System.out.println("process, bitfield_resp_nack: sender is "+sender.getID()+", local is "+node.getID());
+                                       return;
+                               }
+                               /*Request with NACK*/
+                               if(((BitfieldMsg)event).isRequest && !((BitfieldMsg)event).ack){
+                                       //System.out.println("process, bitfield_req_nack: sender is "+sender.getID()+", local is "+node.getID());
+                                       if(alive(sender)){
+                                               Element e = search(sender.getID());
+                                               ev = new BitfieldMsg(BITFIELD, false, true, node, status, nPieces); //response with ack
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                             EDSimulator.add(latency,ev,sender,pid);
+                                               ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                               cache[e.peer].justSent();
+                                       }
+                               }
+                               /*Response with ACK*/
+                               if(!((BitfieldMsg)event).isRequest && ((BitfieldMsg)event).ack){
+                                       nBitfieldSent--;
+                                       //System.out.println("process, bitfield_resp_ack: sender is "+sender.getID()+", local is "+node.getID());
+                                       if(alive(sender)){
+                                               if(addNeighbor(sender)){
+                                                       Element e = search(sender.getID());
+                                                       cache[e.peer].isAlive();
+                                                       swarm[e.peer] = fileStatus;
+                                                       boolean isSeeder = true;
+                                                       for(int i=0; i<nPieces; i++){
+                                                               rarestPieceSet[i]+= fileStatus[i];
+                                                               isSeeder = isSeeder && (fileStatus[i]==1);
+                                                       }
+                                                       e.isSeeder = isSeeder;
+                                                       
+                                                       if(nNodes==10 && !lock){ // I begin to request pieces
+                                                               lock = true;
+                                                               int piece = getPiece();
+                                                               if(piece == -1)
+                                                                       return;
+                                                               lastInterested = piece;
+                                                               currentPiece = lastInterested;
+                                                               ev = new IntMsg(INTERESTED, node, lastInterested,0);
+                                                               for(int i=0; i<swarmSize; i++){// send the interested message to those  
+                                                                                                               // nodes which have that piece
+                                                                       if(alive(cache[i].node) && swarm[i][piece]==1){                                                                         
+//                                                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[i].node);
+//                                                                             EDSimulator.add(latency,ev,cache[i].node,pid);
+                                                                               ((Transport) node.getProtocol(tid)).send(node, cache[i].node, ev, pid);
+                                                                               cache[i].justSent();
+                                                                       }
+                                                               }
+                                                               
+                                                       }
+                                                       
+                                               }
+                                       }
+                                       else
+                                               System.out.println("Sender "+sender.getID()+" not alive");
+                               }
+                               /*Request with ACK*/
+                               if(((BitfieldMsg)event).isRequest && ((BitfieldMsg)event).ack){
+                                       //System.out.println("process, bitfield_req_ack: sender is "+sender.getID()+", local is "+node.getID());
+                                       if(alive(sender)){
+                                               if(addNeighbor(sender)){
+                                                       Element e = search(sender.getID()); 
+                                                       cache[e.peer].isAlive();
+                                                       swarm[e.peer] = fileStatus;
+                                                       boolean isSeeder = true;
+                                                       for(int i=0; i<nPieces; i++){
+                                                               rarestPieceSet[i]+= fileStatus[i]; // I update the rarestPieceSet with the pieces of the new node
+                                                               isSeeder = isSeeder && (fileStatus[i]==1); // I check if the new node is a seeder
+                                                       }
+                                                       e.isSeeder = isSeeder;
+                                                       ev = new BitfieldMsg(BITFIELD, false, true, node, status, nPieces); //response with ack
+//                                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                                     EDSimulator.add(latency,ev,sender,pid);
+                                                       ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                                       cache[e.peer].justSent();
+                                                       if(nNodes==10 && !lock){ // I begin to request pieces
+                                                               int piece = getPiece();
+                                                               if(piece == -1)
+                                                                       return;
+                                                               lastInterested = piece;
+                                                               currentPiece = lastInterested;
+                                                               ev = new IntMsg(INTERESTED, node, lastInterested,0);
+                                                               for(int i=0; i<swarmSize; i++){// send the interested message to those  
+                                                                                                               // nodes which have that piece
+                                                                       if(alive(cache[i].node) && swarm[i][piece]==1){
+//                                                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[i].node);
+//                                                                             EDSimulator.add(latency,ev,cache[i].node,pid);
+                                                                               ((Transport) node.getProtocol(tid)).send(node, cache[i].node, ev, pid);
+                                                                               cache[i].justSent();
+                                                                       }
+                                                               }
+                                                               
+                                                       }
+                                               }
+                                               else {
+                                                       Element e;
+                                                       if((e = search(sender.getID()))!=null){ // The sender was already in the cache
+                                                               cache[e.peer].isAlive();
+                                                               ev = new BitfieldMsg(BITFIELD, false, true, node, status, nPieces); //response with ack
+//                                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                                             EDSimulator.add(latency,ev,sender,pid);
+                                                               ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                                               cache[e.peer].justSent();
+                                                       }
+                                                       else{ // Was not be possible add the sender (nBitfield+nNodes > swarmSize)
+                                                               ev = new BitfieldMsg(BITFIELD, false, false, node, status, nPieces); //response with nack
+//                                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                                             EDSimulator.add(latency,ev,sender,pid);
+                                                               ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                                       }
+                                               }
+                                               
+                                       }
+                                       else
+                                               System.out.println("Sender "+sender.getID()+" not alive");
+                               }
+                       };break;
+                               
+                       case REQUEST: // 8, REQUEST message.
+                       {
+                               Object evnt;
+                               Node sender = ((IntMsg)event).getSender();
+                               int value = ((IntMsg)event).getInt();
+                               Element e;
+                               BitTorrent senderP;
+                               int remoteRate;
+                               int localRate;
+                               int bandwidth;
+                               int downloadTime;
+                               
+                               e = search(sender.getID());
+                               if (e==null)
+                                       return;
+                               cache[e.peer].isAlive();
+                               
+                               requestToServe.enqueue(value, sender);
+                                                               
+                               /*I serve the enqueued requests until 10 uploding pieces or an empty queue*/
+                               while(!requestToServe.empty() && nPiecesUp <10){ 
+                                       Request req = requestToServe.dequeue();
+                                       e = search(req.sender.getID());
+                                       if(e!=null && alive(req.sender)){
+//                                             ev = new IntMsg(PIECE, node, req.id);
+                                               nPiecesUp++;
+                                               e.valueUP++;
+                                               senderP = ((BitTorrent)req.sender.getProtocol(pid));
+                                               senderP.nPiecesDown++;
+                                               remoteRate = senderP.maxBandwidth/(senderP.nPiecesUp + senderP.nPiecesDown);
+                                               localRate = maxBandwidth/(nPiecesUp + nPiecesDown);
+                                               bandwidth = Math.min(remoteRate, localRate);
+                                               downloadTime = ((16*8)/(bandwidth))*1000; // in milliseconds
+                                               
+                                               ev = new IntMsg(PIECE, node, req.id, 16*8 * 1024);
+                                               ((Transport) node.getProtocol(tid)).send(node, req.sender, ev, pid);
+                                               
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,req.sender);
+//                                             EDSimulator.add(latency+downloadTime,ev,req.sender,pid);
+                                               cache[e.peer].justSent();
+                                               
+                                               /*I send to me an event to indicate that the download is completed.
+                                               This prevent that, when the receiver death occurres, my value nPiecesUp
+                                               doesn't decrease.*/
+                                               evnt = new SimpleMsg(DOWNLOAD_COMPLETED, req.sender);
+//                                             EDSimulator.add(latency+downloadTime,evnt,node,pid); 
+                                               ((Transport) node.getProtocol(tid)).send(node, node, evnt, pid);
+                                       }
+                               }
+                       }; break;
+                               
+                       case PIECE: // 9, PIECE message.
+                       {
+                               Node sender = ((IntMsg)event).getSender();
+                               /*      Set the correct value for the local uploading and remote 
+                               downloading number of pieces */
+                               nPiecesDown--;
+                               
+                               if(peerStatus == 1)// To save CPU cycles
+                                       return;
+                               //System.out.println("process, piece: sender is "+sender.getID()+", local is "+node.getID());
+                               Element e = search(sender.getID());
+                               
+                               if(e==null){ //I can't accept a piece not wait
+                                       return;
+                               }
+                               e.valueDOWN++;
+                               
+                               cache[e.peer].isAlive();
+                               
+                               int value = ((IntMsg)event).getInt();
+                               int piece = decode(value,0);
+                               int block = decode(value,1);
+                               /* If the block has not been already downloaded and it belongs to
+                                       the current downloading piece.*/
+                               if(piece == currentPiece && decode(pieceStatus[block],0)!= piece){
+                                       pieceStatus[block] = value;
+                                       status[piece]++;
+                                       removeRequest(value);                                   
+                                       requestNextBlocks(node, pid, e.peer);
+                                       
+                               }else{ // Either a future piece or an owned piece
+                                       if(piece!=currentPiece && status[piece]!=16){ // Piece not owned, will be considered later
+                                               incomingPieces.enqueue(value, sender);
+                                       }
+                                       
+                               }
+                               ev = new IntMsg(CANCEL, node, value,0);
+                               /* I send a CANCEL to all nodes to which I previously requested the block*/
+                               for(int i=0; i<swarmSize; i++){ 
+                                       if(alive(cache[i].node) && unchokedBy[i]==true && swarm[i][decode(block,0)]==1 && cache[i].node != sender){
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[i].node);
+//                                             EDSimulator.add(latency,ev,cache[i].node,pid);
+                                               ((Transport) node.getProtocol(tid)).send(node, cache[i].node, ev, pid);
+                                               cache[i].justSent();
+                                       }
+                               }
+                               
+                               if(status[currentPiece]==16){ // if piece completed, I change the currentPiece to the next wanted                                       
+                                       nPieceCompleted++;
+                                       ev = new IntMsg(HAVE, node, currentPiece,0);
+                                       for(int i=0; i<swarmSize; i++){ // I send the HAVE for the piece
+                                               if(alive(cache[i].node)){
+//                                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[i].node);
+//                                                     EDSimulator.add(latency,ev,cache[i].node,pid);
+                                                       ((Transport) node.getProtocol(tid)).send(node, cache[i].node, ev, pid);
+                                                       cache[i].justSent();
+                                               }
+                                               if(!alive(cache[i].node)){
+                                                       //System.out.println("piece3 rm neigh "+ cache[i].node.getID() );                                                       
+                                                       removeNeighbor(cache[i].node);
+                                                       processNeighborListSize(node,pid);
+                                               }
+                                       }
+                                       ev = new IntMsg(NOT_INTERESTED, node, currentPiece,0);
+                                       for(int i=0; i<swarmSize; i++){ // I send the NOT_INTERESTED to which peer I sent an INTERESTED
+                                               if(swarm[i][piece]==1 && alive(cache[i].node)){
+//                                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[i].node);
+//                                                     EDSimulator.add(latency,ev,cache[i].node,pid);
+                                                       ((Transport) node.getProtocol(tid)).send(node, cache[i].node, ev, pid);
+                                                       cache[i].justSent();
+                                               }
+                                               if(!alive(cache[i].node)){
+                                                       //System.out.println("piece4 rm neigh "+ cache[i].node.getID() );                                                       
+                                                       removeNeighbor(cache[i].node);
+                                                       processNeighborListSize(node,pid);
+                                               }
+                                       }
+                                       if(nPieceCompleted == nPieces){
+                                               System.out.println("FILE COMPLETED for peer "+node.getID());
+                                               this.peerStatus = 1;    
+                                       }
+                                       
+                                       /*      I set the currentPiece to the lastInterested. Then I extract 
+                                               the queued received blocks
+                                               */
+                                       
+                                       currentPiece = lastInterested;
+                                       int m = incomingPieces.dim;
+                                       while(m > 0){ // I process the queue
+                                               m--;
+                                               Request temp = incomingPieces.dequeue();
+                                               int p = decode(temp.id,0); // piece id
+                                               int b = decode(temp.id,1); // block id
+                                               Element s = search(temp.sender.getID());
+                                               if(s==null) // if the node that sent the block in the queue is dead
+                                                       continue;
+                                               if(p==currentPiece && decode(pieceStatus[b],0)!= p){
+                                                       pieceStatus[b] = temp.id;
+                                                       status[p]++;
+                                                       removeRequest(temp.id);
+                                                       requestNextBlocks(node, pid, s.peer);
+                                               }
+                                               else{ // The piece not currently desired will be moved to the tail
+                                                       if(p!= currentPiece) // If not a duplicate block but belongs to another piece
+                                                               incomingPieces.enqueue(temp.id,temp.sender);
+                                                       else // duplicate block
+                                                               requestNextBlocks(node, pid, s.peer);
+                                               }
+                                       }
+                               }
+                       }; break;
+                               
+                       case CANCEL:
+                       {
+                               Node sender = ((IntMsg)event).getSender();
+                               int value = ((IntMsg)event).getInt();
+                               requestToServe.remove(sender, value);
+                       };break;
+                               
+                       case PEERSET: // PEERSET message
+                       {
+                               Node sender = ((PeerSetMsg)event).getSender();
+                               //System.out.println("process, peerset: sender is "+sender.getID()+", local is "+node.getID());
+                               Neighbor n[] = ((PeerSetMsg)event).getPeerSet();
+                               
+                               for(int i=0; i<peersetSize; i++){
+                                       if( n[i]!=null && alive(n[i].node) && search(n[i].node.getID())==null && nNodes+nBitfieldSent <swarmSize-2) {
+                                               ev = new BitfieldMsg(BITFIELD, true, true, node, status, nPieces);
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,n[i].node);
+//                                             EDSimulator.add(latency,ev,n[i].node,pid);
+                                               ((Transport) node.getProtocol(tid)).send(node, n[i].node, ev, pid);
+
+                                               nBitfieldSent++;
+                                               // Here I should call the Neighbor.justSent(), but here
+                                               // the node is not yet in the cache.
+                                       }
+                               }
+                       }; break;
+                               
+                       case TRACKER: // TRACKER message
+                       {
+                               
+                               int j=0;
+                               Node sender = ((SimpleMsg)event).getSender();
+                               //System.out.println("process, tracker: sender is "+sender.getID()+", local is "+node.getID());
+                               if(!alive(sender))
+                                       return;
+                               Neighbor tmp[] = new Neighbor[peersetSize];
+                               int k=0;
+                               if(nNodes <= peersetSize){
+                                       for(int i=0; i< nMaxNodes+maxGrowth; i++){
+                                               if(cache[i].node != null && cache[i].node.getID()!= sender.getID()){
+                                                       tmp[k]=cache[i];
+                                                       k++;
+                                               }
+                                       }
+                                       ev = new PeerSetMsg(PEERSET, tmp, node);
+//                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node, sender);
+//                                     EDSimulator.add(latency,ev,sender,pid);
+                                       ((Transport) node.getProtocol(tid)).send(node,sender, ev, pid);
+                                       return;
+                               }
+                               
+                               while(j < peersetSize){
+                                       int i = CommonState.r.nextInt(nMaxNodes+maxGrowth);
+                                       for (int z=0; z<j; z++){
+                                               if(cache[i].node==null || tmp[z].node.getID() == cache[i].node.getID() || cache[i].node.getID() == sender.getID()){
+                                                       z=0;
+                                                       i= CommonState.r.nextInt(nMaxNodes+maxGrowth);
+                                               }
+                                       }
+                                       if(cache[i].node != null){
+                                               tmp[j] = cache[i];
+                                               j++;
+                                       }
+                               }
+                               ev = new PeerSetMsg(PEERSET, tmp, node);
+//                             latency = ((Transport)node.getProtocol(tid)).getLatency(node, sender);
+//                             EDSimulator.add(latency,ev,sender,pid);
+                               ((Transport) node.getProtocol(tid)).send(node,sender, ev, pid);
+                       }; break;
+                               
+                       case CHOKE_TIME: //Every 10 secs.
+                       {       
+                               n_choke_time++;
+                               
+                               ev = new SimpleEvent(CHOKE_TIME);
+                               EDSimulator.add(10000,ev,node,pid);
+                               int j=0;
+                               /*I copy the interested nodes in the byBandwidth array*/
+                               for(int i=0;i< swarmSize && byPeer[i].peer != -1; i++){
+                                       if(cache[byPeer[i].peer].interested > 0){
+                                               byBandwidth[j]=byPeer[i]; //shallow copy
+                                               j++;
+                                       }
+                               }
+                               
+                               /*It ensures that in the next 20sec, if there are less nodes interested
+                                       than now, those in surplus will not be ordered. */
+                               for(;j<swarmSize;j++){
+                                       byBandwidth[j]=null;
+                               }
+                               sortByBandwidth();
+                               int optimistic = 3;
+                               int luckies[] = new int[3];
+                               try{ // It takes the first three neighbors
+                                       luckies[0] = byBandwidth[0].peer;
+                                       optimistic--;
+                                       luckies[1] = byBandwidth[1].peer;
+                                       optimistic--;
+                                       luckies[2] = byBandwidth[2].peer;
+                               }
+                               catch(NullPointerException e){ // If not enough peer in byBandwidth it chooses the other romdomly 
+                                       for(int z = optimistic; z>0;z--){
+                                               int lucky = CommonState.r.nextInt(nNodes);
+                                               while(cache[byPeer[lucky].peer].status ==1 && alive(cache[byPeer[lucky].peer].node) && 
+                                                         cache[byPeer[lucky].peer].interested == 0)// until the lucky peer is already unchoked or not interested
+                                                       lucky = CommonState.r.nextInt(nNodes);
+                                               luckies[3-z]= byPeer[lucky].peer;
+                                       }
+                               }
+                               for(int i=0; i<swarmSize; i++){ // I perform the chokes and the unchokes
+                                       if((i==luckies[0] || i==luckies[1] || i==luckies[2]) &&  alive(cache[i].node) && cache[i].status != 2){ //the unchokes
+                                               cache[i].status = 1;
+                                               ev = new SimpleMsg(UNCHOKE, node);
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node, cache[i].node);
+//                                             EDSimulator.add(latency,ev,cache[i].node,pid);
+                                               ((Transport) node.getProtocol(tid)).send(node,cache[i].node, ev, pid);
+                                               cache[i].justSent();
+                                               //System.out.println("average time, unchoked: "+cache[i].node.getID());
+                                       }
+                                       else{ // the chokes
+                                               if(alive(cache[i].node) && (cache[i].status == 1 || cache[i].status == 2)){
+                                                       cache[i].status = 0;
+                                                       ev = new SimpleMsg(CHOKE, node);
+//                                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node, cache[i].node);
+//                                                     EDSimulator.add(latency,ev,cache[i].node,pid);
+                                                       ((Transport) node.getProtocol(tid)).send(node,cache[i].node, ev, pid);
+                                                       cache[i].justSent();
+                                               }
+                                       }
+                               }
+                               
+                               if(n_choke_time%2==0){ //every 20 secs. Used in computing the average download rates
+                                       for(int i=0; i<nNodes; i++){
+                                               if(this.peerStatus == 0){ // I'm a leeacher
+                                                       byPeer[i].head20 = byPeer[i].valueDOWN;
+                                               }
+                                               else{
+                                                       byPeer[i].head20 = byPeer[i].valueUP;
+                                               }
+                                       }
+                               }
+                       }; break;
+                               
+                       case OPTUNCHK_TIME:
+                       {
+                               
+                               //System.out.println("process, optunchk_time");
+                               
+                               ev = new SimpleEvent(OPTUNCHK_TIME);
+                               EDSimulator.add(30000,ev,node,pid);
+                               int lucky = CommonState.r.nextInt(nNodes);
+                               while(cache[byPeer[lucky].peer].status ==1)// until the lucky peer is already unchoked
+                                       lucky = CommonState.r.nextInt(nNodes);
+                               if(!alive(cache[byPeer[lucky].peer].node))
+                                       return;
+                               cache[byPeer[lucky].peer].status = 1;
+                               Object msg = new SimpleMsg(UNCHOKE,node);
+//                             latency = ((Transport)node.getProtocol(tid)).getLatency(node, cache[byPeer[lucky].peer].node);
+//                             EDSimulator.add(latency,msg,cache[byPeer[lucky].peer].node,pid);
+                               ((Transport) node.getProtocol(tid)).send(node,cache[byPeer[lucky].peer].node, msg, pid);
+                               cache[byPeer[lucky].peer].justSent();
+                       }; break;
+                               
+                       case ANTISNUB_TIME:
+                       {
+                               if(this.peerStatus == 1) // I'm a seeder, I don't update the event
+                                       return;
+                               //System.out.println("process, antisnub_time");
+                               for(int i=0; i<nNodes; i++){
+                                       if(byPeer[i].valueDOWN >0 && (byPeer[i].valueDOWN - byPeer[i].head60)==0){// No blocks downloaded in 1 min
+                                               cache[byPeer[i].peer].status = 2; // I'm snubbed by it
+                                       }
+                                       byPeer[i].head60 = byPeer[i].valueDOWN;
+                               }
+                               ev = new SimpleEvent(ANTISNUB_TIME);
+                               EDSimulator.add(60000,ev,node,pid);
+                               long time = CommonState.getTime();
+                       }; break;
+                               
+                       case CHECKALIVE_TIME:
+                       {
+                               
+                               //System.out.println("process, checkalive_time");
+                               
+                               long now = CommonState.getTime();
+                               for(int i=0; i<swarmSize; i++){
+                                       /*If are at least 2 minutes (plus 1 sec of tolerance) that
+                                       I don't send anything to it.*/
+                                       if(alive(cache[i].node) && (cache[i].lastSent < (now-121000))){
+                                               Object msg = new IntMsg(KEEP_ALIVE,node,0,0);
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node, cache[i].node);
+//                                             EDSimulator.add(latency,msg,cache[i].node,pid);
+                                               ((Transport) node.getProtocol(tid)).send(node,cache[i].node, msg, pid);
+                                               cache[i].justSent();
+                                       }
+                                       /*If are at least 2 minutes (plus 1 sec of tolerance) that I don't
+                                       receive anything from it though I sent a keepalive 2 minutes ago*/
+                                       else{
+                                               if(cache[i].lastSeen <(now-121000) && cache[i].node != null && cache[i].lastSent < (now-121000)){
+                                                       System.out.println("process, checkalive_time, rm neigh " + cache[i].node.getID());
+                                                       if(cache[i].node.getIndex() != -1){
+                                                               System.out.println("This should never happen: I remove a node that is not effectively died");
+                                                       }
+                                                       removeNeighbor(cache[i].node);
+                                                       processNeighborListSize(node,pid);
+                                               }
+                                       }
+                               }
+                               ev = new SimpleEvent(CHECKALIVE_TIME);
+                               EDSimulator.add(120000,ev,node,pid);
+                       }; break;
+                               
+                       case TRACKERALIVE_TIME:
+                       {
+                               //System.out.println("process, trackeralive_time");
+                               if(alive(tracker)){
+                                       ev = new SimpleEvent(TRACKERALIVE_TIME);
+                                       EDSimulator.add(1800000,ev,node,pid);
+                               }
+                               else
+                                       tracker=null;
+                               
+                       }; break;
+                               
+                       case DOWNLOAD_COMPLETED:
+                       {
+                               nPiecesUp--;
+                       }; break;
+                               
+               }
+       }
+       
+       /**
+        *      Given a piece index and a block index it encodes them in an unique integer value.
+        *      @param piece the index of the piece to encode.
+        *      @param block the index of the block to encode.
+        *      @return the encoding of the piece and the block indexes.
+        */
+       private int encode(int piece, int block){
+               return (piece*100)+block;
+               
+       }
+       /** 
+        *      Returns either the piece or the block that contained in the <tt>value</tt> depending
+        *      on <tt>part</tt>: 0 means the piece value, 1 the block value.
+        *      @param value the ID of the block to decode.
+        *      @param part the information to extract from <tt>value</tt>. 0 means the piece index, 1 the block index.
+        *      @return the piece or the block index depending about the value of <tt>part</tt>
+        */
+       private int decode(int value, int part){
+               if (value==-1) // Not a true value to decode
+                       return -1;
+               if(part == 0) // I'm interested to the piece
+                       return value/100;
+               else // I'm interested to the block
+                       return value%100;
+       }
+       
+       /**
+        *      Used by {@link NodeInitializer#choosePieces(int, BitTorrent) NodeInitializer} to set 
+        *      the number of piece completed from the beginning in according with
+        *      the distribution in the configuration file.
+        *      @param number the number of piece completed
+        */
+       public void setCompleted(int number){
+               this.nPieceCompleted = number;
+       }
+       
+       /**
+        *      Sets the status (the set of blocks) of the file for the current node.
+        *  Note that a piece is considered <i>completed</i> if the number
+        *  of downloaded blocks is 16.
+        *  @param index The index of the piece
+        *  @param value Number of blocks downloaded for the piece index.
+        */
+       public void setStatus(int index, int value){
+               status[index]=value;
+       }
+       
+       /**
+        *      Sets the status of the local node.
+        *      @param status The status of the node: 1 means seeder, 0 leecher
+        */
+       public void setPeerStatus(int status){
+               this.peerStatus = status;
+       }
+       
+       /**
+        *      Gets the status of the local node.
+        *      @return The status of the local node: 1 means seeder, 0 leecher
+        */
+       public int getPeerStatus(){
+               return peerStatus;
+       }
+       
+       /**
+        *  Gets the number of blocks for a given piece owned by the local node.
+        *      @param index The index of the piece
+        *      @return Number of blocks downloaded for the piece index
+        */
+       public int getStatus(int index){
+               return status[index];   
+       }
+       
+       /**
+        *      Sets the maximum bandwdith for the local node.
+        *      @param value The value of bandwidth in Kbps
+        */
+       public void setBandwidth(int value){
+               maxBandwidth = value;
+       }
+       
+       /**
+        *      Checks if a node is still alive in the simulated network.
+        *      @param node The node to check
+        *      @return true if the node <tt>node</tt> is up, false otherwise
+        *      @see peersim.core.GeneralNode#isUp
+        */
+       public boolean alive(Node node){
+               if(node == null)
+                       return false;
+               else
+                       return node.isUp();
+       }
+               
+       /**     
+        *      Adds a neighbor to the cache of the local node.
+        *  The new neighbor is put in the first null position.
+        *      @param neighbor The neighbor node to add
+        *  @return <tt>false</tt> if the neighbor is already present in the cache (this can happen when the peer requests a
+        *      new peer set to the tracker an there is still this neighbor within) or no place is available.
+        *      Otherwise, returns true if the node is correctly added to the cache.
+        */
+       public boolean addNeighbor(Node neighbor){
+               if(search(neighbor.getID()) !=null){// if already exists
+               //      System.err.println("Node "+neighbor.getID() + " not added, already exist.");
+                       return false;
+               }
+               if(this.tracker == null){ // I'm in the tracker's BitTorrent protocol
+                       for(int i=0; i< nMaxNodes+maxGrowth; i++){
+                               if(cache[i].node == null){
+                                       cache[i].node = neighbor;
+                                       cache[i].status = 0; //chocked
+                                       cache[i].interested = -1; //not interested
+                                       this.nNodes++;
+                                       
+                                       //System.err.println("i: " + i +" nMaxNodes: " + nMaxNodes);
+                                       return true;
+                               }
+                       }
+               }
+               else{
+                       if((nNodes+nBitfieldSent) < swarmSize){
+                               //System.out.println("I'm the node " + this.thisNodeID + ", trying to add node "+neighbor.getID());
+                               for(int i=0; i<swarmSize; i++){
+                                       if(cache[i].node == null){
+                                               cache[i].node = neighbor;
+                                               cache[i].status = 0; //choked
+                                               cache[i].interested = -1; // not interested
+                                               byPeer[nNodes].peer = i;
+                                               byPeer[nNodes].ID = neighbor.getID();
+                                               sortByPeer();
+                                               this.nNodes++;
+                                               //System.out.println(neighbor.getID()+" added!");
+                                               return true;
+                                       }
+                               }
+                               System.out.println("Node not added, no places available");
+                       }
+               }
+               return false;
+       }
+       
+       /**
+        *      Removes a neighbor from the cache of the local node.
+        *      @param neighbor The node to remove
+        *      @return true if the node is correctly removed, false otherwise.
+     */
+       public boolean removeNeighbor(Node neighbor) {
+               
+               if (neighbor == null)
+                       return true;
+               
+               // this is the tracker's bittorrent protocol
+               if (this.tracker == null) {
+                       for (int i=0; i< (nMaxNodes+maxGrowth); i++) {
+                               
+                               // check the feasibility of the removal
+                               if ( (cache[i] != null) && (cache[i].node != null) &&
+                                        (cache[i].node.getID() == neighbor.getID()) ) {
+                                       cache[i].node = null;
+                                       this.nNodes--;
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
+               // this is the bittorrent protocol of a peer
+               else {
+                       
+                       Element e = search(neighbor.getID());
+                       
+                       if (e != null) {
+                               for (int i=0; i<nPieces; i++) {
+                                       rarestPieceSet[i] -= swarm[e.peer][i];
+                                       swarm[e.peer][i] = 0;
+                               }
+                               
+                               cache[e.peer].node = null;
+                               cache[e.peer].status = 0;
+                               cache[e.peer].interested = -1;
+                               unchokedBy[e.peer] = false;
+                               this.nNodes--;
+                               e.peer = -1;
+                               e.ID = Integer.MAX_VALUE;
+                               e.valueUP = 0;
+                               e.valueDOWN = 0;
+                               e.head20 = 0;
+                               e.head60 = 0;
+                               sortByPeer();
+                               
+                               return true;
+                       }
+               }
+               return false;
+       }
+       
+       /**
+     * Adds a request to the pendingRequest queue.
+        *      @param block The requested block
+        *      @return true if the request has been successfully added to the queue, false otherwise
+        */
+       private boolean addRequest(int block){
+               int i=4;
+               while(i>=0 && pendingRequest[i]!=-1){
+                       i--;
+               }
+               if(i>=0){
+                       pendingRequest[i] = block;
+                       return true;
+               }
+               else { // It should never happen
+                          //System.err.println("pendingRequest queue full");
+                       return false;           
+               }
+       }
+       
+       /**
+        *      Removes the block with the given <tt>id</tt> from the {@link #pendingRequest} queue
+        *  and sorts the queue leaving the empty cell at the left.
+        *      @param id the id of the requested block
+        */
+       private void removeRequest(int id){
+               int i = 4;
+               for(; i>=0; i--){
+                       if(pendingRequest[i]==id)
+                               break;
+               }
+               for(; i>=0; i--){
+                       if(i==0)
+                               pendingRequest[i] = -1;
+                       else
+                               pendingRequest[i] = pendingRequest[i-1];
+               }
+       }
+       
+       /**
+        *      Requests new block until the {@link #pendingRequest} is full to the sender of the just received piece.
+        *      It calls {@link #getNewBlock(Node, int)} to implement the <i>strict priority</i> strategy. 
+        *      @param node the local node
+        *      @param pid the BitTorrent protocol id
+        *      @param sender the sender of the just received received piece. 
+        */
+       private void requestNextBlocks(Node node, int pid, int sender){
+               int block = getNewBlock(node, pid);
+               while(block != -2){
+                       if(unchokedBy[sender]==true && alive(cache[sender].node) && addRequest(block)){
+                               Object ev = new IntMsg(REQUEST, node, block,0);
+                               
+//                             long latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[sender].node);
+//                             EDSimulator.add(latency,ev,cache[sender].node,pid);
+                               
+                               ((Transport) node.getProtocol(tid)).send(node,cache[sender].node, ev, pid);
+                               cache[sender].justSent();
+                       }
+                       else{ // I cannot send request
+                               if(!alive(cache[sender].node) && cache[sender].node!=null){
+                                       System.out.println("piece2 rm neigh "+ cache[sender].node.getID() );
+                                       removeNeighbor(cache[sender].node);
+                                       processNeighborListSize(node,pid);
+                               }
+                               return;
+                       }
+                       block = getNewBlock(node, pid);
+               }
+       }
+       
+       /**
+        *      It returns the id of the next block to request. Sends <tt>INTERESTED</tt> if the new
+        *      block belongs to a new piece.
+        *      It uses {@link #getBlock()} to get the next block of a piece and calls {@link #getPiece()}
+        *      when all the blocks for the {@link #currentPiece} have been requested.
+        *      @param node the local node
+        *      @param pid the BitTorrent protocol id
+        *      @return -2 if no more places available in the <tt>pendingRequest</tt> queue;<br/>
+        *                      the value of the next block to request otherwise</p>
+        */
+       private int getNewBlock(Node node, int pid){
+               int block = getBlock();
+               if(block < 0){ // No more block to request for the current piece 
+                       
+                       if(block ==-2) // Pending request queue full
+                               return -2;
+                       
+                       int newPiece = getPiece();
+                       if(newPiece == -1){ // no more piece to request
+                               return -2;
+                       }
+                       
+                       lastInterested = newPiece;
+                       Object ev = new IntMsg(INTERESTED, node, lastInterested,0);
+                       
+                       for(int j=0; j<swarmSize; j++){// send the interested message to those  
+                                                                       // nodes which have that piece
+                               if(alive(cache[j].node) && swarm[j][newPiece]==1){
+//                                     long latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[j].node);
+//                                     EDSimulator.add(latency,ev,cache[j].node,pid);
+                                       ((Transport) node.getProtocol(tid)).send(node,cache[j].node, ev, pid);
+                                       cache[j].justSent();
+                               }
+                               if(!alive(cache[j].node)){
+                                       //System.out.println("piece1 rm neigh "+ cache[j].node.getID() );
+                                       
+                                       removeNeighbor(cache[j].node);
+                                       processNeighborListSize(node,pid);
+                               }
+                       }
+                       block = getBlock();
+                       return block;
+               }
+               else{
+                       // block value referred to a real block
+                       return block;
+               }
+       }
+       
+       /**
+        *      Returns the next block to request for the {@link #currentPiece}.
+        *      @return an index of a block of the <tt>currentPiece</tt> if there are still 
+        *                      available places in the {@link #pendingRequest} queue;<br/>
+        *                      -2 if the <tt>pendingRequest</tt> queue is full;<br/>
+        *                      -1 if no more blocks to request for the current piece. 
+        */
+       private int getBlock(){
+               int i=4;
+               while(i>=0 && pendingRequest[i]!=-1){ // i is the first empty position from the head
+                       i--;
+               }
+               if(i==-1){// No places in the pendingRequest available
+                                 //System.out.println("Pendig request queue full!");
+                       return -2;
+               }
+               int j;
+               //The queue is not empty & last requested block belongs to lastInterested piece 
+               if(i!=4 && decode(pendingRequest[i+1],0)==lastInterested)
+                       j=decode(pendingRequest[i+1],1)+1; // the block following the last requested
+               else // I don't know which is the next block, so I search it.
+                       j=0; 
+               /*      I search another block until the current has been already received. 
+                       *       If in pieceStatus at position j there is a block that belongs to
+                       *       lastInterested piece, means that the block j has been already
+                       *       received, otherwise I can request it.
+                       */
+               while(j<16 && decode(pieceStatus[j],0)==lastInterested){
+                       j++;
+               }
+               if(j==16) // No more block to request for lastInterested piece
+                       return -1;
+               return encode(lastInterested,j);
+       }
+       
+       /**
+        *      Returns the next correct piece to download. It choose the piece by using the
+        *      <i>random first</i> and <i>rarest first</i> policy. For the beginning 4 pieces
+        *      of a file the first one is used then the pieces are chosen using <i>rarest first</i>.
+        *      @see "Documentation about the BitTorrent module"
+        *      @return the next piece to download. If the whole file has been requested
+        *      -1 is returned.
+        */
+       private int getPiece(){
+               int piece = -1;
+               if(nPieceCompleted < 4){ //Uses random first piece
+                       piece = CommonState.r.nextInt(nPieces);
+                       while(status[piece]==16 || piece == currentPiece) // until the piece is owned
+                               piece = CommonState.r.nextInt(nPieces);
+                       return piece;
+               }
+               else{ //Uses rarest piece first
+                       int j=0;
+                       for(; j<nPieces; j++){ // I find the first not owned piece
+                               if(status[j]==0){
+                                       piece = j;
+                                       if(piece != lastInterested) // teoretically it works because
+                                                                                               // there should be only one interested 
+                                                                                               // piece not yet downloaded
+                                               break;
+                               }
+                       }
+                       if(piece==-1){ // Never entered in the previous 'if' statement; for all
+                                                  // pieces an has been sent
+                               return -1;
+                       }
+                       
+                       int rarestPieces[] = new int[nPieces-j]; // the pieces with the less number of occurences\
+                       rarestPieces[0] = j;
+                       int nValues = 1; // number of pieces less distributed in the network
+                       for(int i=j+1; i<nPieces; i++){ // Finds the rarest piece not owned
+                               if(rarestPieceSet[i]< rarestPieceSet[rarestPieces[0]] && status[i]==0){ // if strictly less than the current one
+                                       rarestPieces[0] = i; 
+                                       nValues = 1;
+                               }
+                               if(rarestPieceSet[i]==rarestPieceSet[rarestPieces[0]] && status[i]==0){ // if equal
+                                       rarestPieces[nValues] = i;
+                                       nValues++;
+                               }
+                       }
+                       
+                       piece = CommonState.r.nextInt(nValues); // one of the less owned pieces
+                       return rarestPieces[piece];
+               }
+       }
+       
+       /**
+        *      Returns the file's size as number of pieces of 256KB.
+        *      @return number of pieces that compose the file.
+        */
+       public int getNPieces(){
+               return nPieces; 
+       }
+       /**
+        *      Clone method of the class. Returns a deep copy of the BitTorrent class. Used
+        *      by the simulation to initialize the {@link peersim.core.Network}
+        *      @return the deep copy of the BitTorrent class.
+        */
+       public Object clone(){
+               Object prot = null;
+               try{
+                       prot = (BitTorrent)super.clone();
+               }
+               catch(CloneNotSupportedException e){};
+               
+               ((BitTorrent)prot).cache = new Neighbor[swarmSize];
+               for(int i=0; i<swarmSize; i++){
+                       ((BitTorrent)prot).cache[i] = new Neighbor();
+               }
+               
+               ((BitTorrent)prot).byPeer = new Element[swarmSize];
+               for(int i=0; i<swarmSize; i++){
+                       ((BitTorrent)prot).byPeer[i] = new Element();
+               }
+               
+               ((BitTorrent)prot).unchokedBy = new boolean[swarmSize];
+               
+               ((BitTorrent)prot).byBandwidth = new Element[swarmSize];
+               ((BitTorrent)prot).status = new int[nPieces];
+               ((BitTorrent)prot).pieceStatus = new int[16];
+               for(int i=0; i<16;i++)
+                       ((BitTorrent)prot).pieceStatus[i] = -1;
+               ((BitTorrent)prot).pendingRequest = new int[5];
+               for(int i=0; i<5;i++)
+                       ((BitTorrent)prot).pendingRequest[i] = -1;
+               ((BitTorrent)prot).rarestPieceSet = new int[nPieces];
+               for(int i=0; i<nPieces;i++)
+                       ((BitTorrent)prot).rarestPieceSet[i] = 0;
+               ((BitTorrent)prot).swarm = new int[swarmSize][nPieces];
+               ((BitTorrent)prot).requestToServe = new Queue(20);
+               ((BitTorrent)prot).incomingPieces = new Queue(100);
+               return prot;
+       }
+       
+       /**
+        *      Sorts {@link #byPeer} array by peer's ID. It implements the <i>InsertionSort</i>
+        *      algorithm. 
+        */
+       public void sortByPeer(){
+               int i;
+               
+               for(int j=1; j<swarmSize; j++)   // out is dividing line
+               {
+                       Element key = new Element(); 
+                       byPeer[j].copyTo(key) ;    // remove marked item
+                       i = j-1;           // start shifts at out
+                       while(i>=0 && (byPeer[i].ID > key.ID)) // until one is smaller,
+                       {
+                               byPeer[i].copyTo(byPeer[i+1]);      // shift item right,
+                               i--;            // go left one position
+                       }
+                       key.copyTo(byPeer[i+1]);         // insert marked item
+               } 
+               
+       }
+       
+       /**
+        *      Sorts the array {@link #byBandwidth} using <i>QuickSort</i> algorithm.
+        *      <tt>null</tt> elements and seeders are moved to the end of the array.
+        */
+       public void sortByBandwidth() {
+        quicksort(0, swarmSize-1);
+    }
+       
+       /**
+        *      Used by {@link #sortByBandwidth()}. It's the implementation of the
+        *      <i>QuickSort</i> algorithm.
+        *      @param left the leftmost index of the array to sort.
+        *      @param right the rightmost index of the array to sort.
+        */
+       private void quicksort(int left, int right) {
+        if (right <= left) return;
+        int i = partition(left, right);
+        quicksort(left, i-1);
+        quicksort(i+1, right);
+    }
+       
+       /**
+        *      Used by {@link #quicksort(int, int)}, partitions the subarray to sort returning
+        *      the splitting point as stated by the <i>QuickSort</i> algorithm.
+        *      @see "The <i>QuickSort</i> algorithm".
+        */
+       private int partition(int left, int right) {
+        int i = left - 1;
+        int j = right;
+        while (true) {
+            while (greater(byBandwidth[++i], byBandwidth[right]))      // find item on left to swap
+                ;                               // a[right] acts as sentinel
+            while (greater(byBandwidth[right], byBandwidth[--j])) {      // find item on right to swap
+                if (j == left) break;  // don't go out-of-bounds
+                       }
+            if (i >= j) break;                  // check if pointers cross
+            swap(i, j);                      // swap two elements into place
+        }
+        swap(i, right);                      // swap with partition element
+        return i;
+    }
+       
+       /**
+        *      Aswers to the question "is x > y?". Compares the {@link Element}s given as 
+        *      parameters. <tt>Element x</tt> is greater than <tt>y</tt> if isn't <tt>null</tt>
+        *      and in the last 20 seconds the local node has downloaded ("uploaded" if the local node is a 
+        *      seeder) more blocks than from <tt>y</tt>.
+        *      @param x the first <tt>Element</tt> to compare.
+        *      @param y the second <tt>Element</tt> to compare
+        *      @return <tt>true</tt> if x > y;<br/>
+        *                      <tt>false</tt> otherwise.
+        */
+    private boolean greater(Element x, Element y) {
+               /*
+                * Null elements and seeders are shifted at the end
+                * of the array
+                */
+               if (x==null) return false;
+               if (y==null) return true;
+               if (x.isSeeder) return false;
+               if (y.isSeeder) return true;
+               
+               // if the local node is a leecher
+               if (peerStatus==0) {
+                       if ((x.valueDOWN - x.head20) >
+                               (y.valueDOWN -y.head20))
+                               return true;
+                       else return false;
+               }
+               
+               // if peerStatus==1 (the local node is a seeder)
+               else {                  
+                       if ((x.valueUP - x.head20) >
+                               (y.valueUP -y.head20))
+                               return true;
+                       else return false;
+               }
+    }
+       
+       /**
+        *      Swaps {@link Element} <tt>i</tt> with <tt>j</tt> in the {@link #byBandwidth}.<br/>
+        *      Used by {@link #partition(int, int)}
+        *      @param i index of the first element to swap
+        *      @param j index of the second element to swap
+        */
+       private void swap(int i, int j) {
+        Element swap = byBandwidth[i];
+        byBandwidth[i] = byBandwidth[j];
+        byBandwidth[j] = swap;
+    }
+       
+       /**     Searches the node with the given ID. It does a dychotomic 
+        *      search.
+        *      @param ID ID of the node to search.
+        *      @return the {@link Element} in {@link #byPeer} which represents the node with the
+        *      given ID.
+        */
+       public Element search(long ID){
+               int low = 0;
+               int high = swarmSize-1;
+               int p = low+((high-low)/2);              //Initial probe position
+               while ( low <= high) {
+                       if ( byPeer[p] == null || byPeer[p].ID > ID)
+                               high = p - 1;
+                       else { 
+                               if( byPeer[p].ID < ID )  //Wasteful second comparison forced by syntax limitations.
+                                       low = p + 1;
+                               else
+                                       return byPeer[p];
+                       }
+                       p = low+((high-low)/2);         //Next probe position.
+               }
+               return null;    
+       }
+}
+
+/**
+ *     This class is used to store the main informations about a neighbors regarding
+ *     the calculation of the Downloading/Uploading rates. Is the class of items in 
+ *     {@link example.bittorrent.BitTorrent#byPeer} and {@link example.bittorrent.BitTorrent#byBandwidth}.
+ */
+class Element{
+       /**
+        *      ID of the represented node.
+        */
+       public long ID = Integer.MAX_VALUE;
+       /**
+        *      Index position of the node in the {@link example.bittorrent.BitTorrent#cache} array.
+        */
+       public int peer = -1; 
+       /**
+        *      Number of blocks uploaded to anyone since the beginning.
+        */
+       public int valueUP = 0;
+       /**
+        *      Number of blocks downloaded from anyone since the beginning.
+        */
+       public int valueDOWN = 0; 
+       /**
+        *      Value of either {@link #valueUP} or {@link #valueDOWN} (depending by 
+        *      {@link example.bittorrent.BitTorrent#peerStatus}) 20 seconds before.
+        */
+       public int head20 = 0;
+       /**
+        *      Value of either {@link #valueUP} or {@link #valueDOWN} (depending by 
+        *      {@link example.bittorrent.BitTorrent#peerStatus}) 60 seconds before.
+        */
+       public int head60 = 0; 
+       /**
+        *      <tt>true</tt> if the node is a seeder, <tt>false</tt> otherwise.
+        */
+       public boolean isSeeder = false;
+       /**
+        *      Makes a deep copy of the Element to <tt>destination</tt>
+        *      @param destination Element instance where to make the copy
+        */
+       public void copyTo(Element destination){
+               destination.ID = this.ID;
+               destination.peer = this.peer;
+               destination.valueUP = this.valueUP;
+               destination.valueDOWN = this.valueDOWN;
+               destination.head20 = this.head20;
+               destination.head60 = this.head60;
+       }
+}
+
+/**
+ *     This class stores information about the neighbors regarding their status. It is 
+ *     the type of the items in the {@link example.bittorrent.BitTorrent#cache}.
+ */
+class Neighbor{
+       /**
+        *      Reference to the node in the {@link peersim.core.Network}.
+        */
+       public Node node = null;
+       /**
+        *      -1 means not interested<br/>
+        *      Other values means the last piece number for which the node is interested.
+        */
+       public int interested;
+       /**
+        *      0 means CHOKED<br/>
+        *      1 means UNCHOKED<br/>
+        *      2 means SNUBBED_BY. If this value is set and the node is to be unchocked,
+        *      value 2 has the priority.
+        */
+       public int status;
+       /**
+        *      Last time a message from the node represented has been received.
+        */
+       public long lastSeen = 0; 
+       /**
+        *      Last time a message to the node represented has been sent.
+        */
+       public long lastSent = 0;
+       
+       /**
+        * Sets the last time the neighbor was seen.
+        */
+       public void isAlive(){
+               long now = CommonState.getTime();
+               this.lastSeen = now;
+       }
+       
+       /*
+        * Sets the last time the local peer sent something to the neighbor.
+        */
+       public void justSent(){
+               long now = CommonState.getTime();
+               this.lastSent = now;
+       }
+       
+}
+
+/**
+ *     Class type of the queues's items in {@link example.bittorrent.BitTorrent#incomingPieces} 
+ *     and {@link example.bittorrent.BitTorrent#requestToServe}.
+ */
+class Queue{
+       int maxSize;
+       int head = 0;
+       int tail = 0;
+       int dim = 0;
+       Request queue[];
+       
+       /**
+        *      Public constructor. Creates a queue of size <tt>size</tt>.
+        */
+       public Queue(int size){
+               maxSize = size;
+               queue = new Request[size];
+               for(int i=0; i< size; i++)
+                       queue[i]= new Request();
+       }
+       
+       /**
+        *      Enqueues the request of the block <tt>id</tt> and its <tt>sender</tt>
+        *      @param id the id of the block in the request
+        *      @param sender a reference to the sender of the request
+        *      @return <tt>true</tt> if the request has been correctly added, <tt>false</tt>
+        *      otherwise.
+        */
+       public boolean enqueue(int id, Node sender){
+               if(dim < maxSize){
+                       queue[tail%maxSize].id = id;
+                       queue[tail%maxSize].sender = sender;
+                       tail++;
+                       dim++;
+                       return true;
+               }
+               else return false;
+       }
+       
+       /**
+        *      Returns the {@link Request} in the head of the queue.
+        *      @return the element in the head.<br/>
+        *                      <tt>null</tt> if the queue is empty.
+        */
+       public Request dequeue(){
+               Request value;
+               if(dim > 0){
+                       value = queue[head%maxSize];
+                       head++;
+                       dim--;
+                       return value;
+               }
+               else return null; //empty queue
+       }
+       
+       /**
+        *      Returns the status of the queue.
+        *      @return <tt>true</tt> if the queue is empty, <tt>false</tt>
+        *      otherwise.
+        */
+       public boolean empty(){
+               return (dim == 0);
+       }
+       
+       /**
+        *      Returns <tt>true</tt> if block given as parameter is in.
+        *      @param  value the id of the block to search.
+        *      @return <tt>true</tt> if the block <tt>value</tt> is in the queue, <tt>false</tt>
+        *      otherwise.
+        */
+       public boolean contains(int value){
+               if(empty())
+                       return false;
+               for(int i=head; i<head+dim; i++){
+                       if(queue[i%maxSize].id == value)
+                               return true;
+               }
+               return false;
+       }
+       
+       /**
+        *      Removes a request from the queue.
+        *      @param sender the sender of the request.
+        *      @param value the id of the block requested.
+        *      @return <tt>true</tt> if the request has been correctly removed, <tt>false</tt>
+        *      otherwise.
+        */
+       public boolean remove(Node sender, int value){
+               if(empty())
+                       return false;
+               for(int i=head; i<head+dim; i++){
+                       if(queue[i%maxSize].id == value && queue[i%maxSize].sender == sender){
+                               for(int j=i; j>head; j--){ // Shifts the elements for the removal
+                                       queue[j%maxSize]= queue[(j-1)%maxSize];
+                               }
+                               head++;
+                               dim--;
+                               return true;
+                       }
+               }
+               return false;
+       }
+}
+
+/**
+ *     This class represent an enqueued request of a block.
+ */
+class Request{
+       /**
+        *      The id of the block.
+        */
+       public int id;
+       /**
+        *      The sender of the request.
+        */
+       public Node sender;
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/bittorrent/BitfieldMsg.java b/contrib/psg/src/example/bittorrent/BitfieldMsg.java
new file mode 100644 (file)
index 0000000..d459482
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --
+ *
+ * Please send your questions/suggestions to:
+ * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it
+ *
+ */
+
+package example.bittorrent;
+
+import peersim.core.*;
+
+/**
+ *     This class is a {@link SimpleMsg} and represents the <tt>bitfield</tt>
+ *     message.
+ */
+public class BitfieldMsg extends SimpleMsg{
+       /**
+        *      The status of the file to transmit to neighbors nodes
+        */
+       int[] array;
+       
+       /**
+        *      Defines the type of the Bitfield message. If <tt>isRequest</tt> is true, then
+        *      the message is a request of subscription; otherwise the message is a response.
+        */
+       boolean isRequest;
+       
+       /**
+        *      <p>The ACK value used to implement <i>ack</i> and <i>nack</i> messages.</p>
+        *      <p>It has value <tt>true</tt> if the message is a reponse and the sender has inserted
+        *      the receiver in its own cache of neighbors.<br/>
+        *      If for some reason (for instance the cache had already 80 peer inside at the moment of the
+        *      request) it was not possible to insert the peer, the value is <tt>false</tt>.<br/>
+        *      It has value <tt>false</tt> also if the message is a request and is sent when occours
+        *      an unespected message.
+        *      </p>
+        *      @see "The documentation to understand the 4 different types of Bitfield messages"
+        */
+       boolean ack;
+       
+       /**
+        *      The basic constructor of the Bitfield message.
+        *      @param type The type of the message, according to {@link SimpleMsg}
+        *      @param isRequest Defines if the message is a request or not
+        *      @param ack Defines if the message type is an <i>ack</i> or a <i>nack</i>
+        *      @param sender The sender node
+        *      @param source The array containing the status of the file
+        *      @param size The size of the array
+        */
+       public BitfieldMsg(int type, boolean isRequest, boolean ack, Node sender, int source[], int size){
+               super.type = type;
+               super.sender = sender;
+               this.isRequest = isRequest;
+               this.ack = ack;
+               this.array = new int[size];
+               for(int i=0; i<size;i++){ // it sends a copy
+                       if(source[i]==16)
+                               this.array[i] = 1;
+                       else
+                               this.array[i] = 0;
+               }
+       }
+       
+       /**
+        *      Gets the array containing the status of the file.
+        *      @return The status of the file
+        */
+       public int[] getArray(){
+               return this.array;      
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/bittorrent/IntMsg.java b/contrib/psg/src/example/bittorrent/IntMsg.java
new file mode 100644 (file)
index 0000000..a10eaea
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --
+ *
+ * Please send your questions/suggestions to:
+ * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it
+ *
+ */
+
+package example.bittorrent;
+
+import peersim.core.*;
+import psgsim.Sizable;
+
+/**
+ * This class is a {@link SimpleMsg} and acts as a container for a message that
+ * uses only an integer value.
+ */
+public class IntMsg extends SimpleMsg implements Sizable {
+
+       /**
+        * The data value (an integer) contained in the message.
+        */
+       private int integer;
+       private double size;
+
+       /**
+        * The basic constructor of the message.
+        *
+        * @param type
+        *            the type of the message
+        * @param sender
+        *            The sender node
+        * @param value
+        *            The data value of the message
+        */
+       public IntMsg(int type, Node sender, int value, double size) {
+               super.type = type;
+               super.sender = sender;
+               this.integer = value;
+               this.size = size;
+       }
+
+       /**
+        * Gets the value contained in the message.
+        *
+        * @return the integer value contained in the message
+        */
+       public int getInt() {
+               return this.integer;
+       }
+
+       @Override
+       public double getSize() {
+               // TODO Auto-generated method stub
+               return size;
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/bittorrent/NetworkDynamics.java b/contrib/psg/src/example/bittorrent/NetworkDynamics.java
new file mode 100644 (file)
index 0000000..bdbd93a
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --
+ *
+ * Please send your questions/suggestions to:
+ * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it
+ *
+ */
+
+package example.bittorrent;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.transport.*;
+import peersim.edsim.*;
+
+/**
+ * This {@link Control} can change the size of networks by adding and removing
+ * nodes. This class supports only permanent removal of nodes and the addition
+ * of brand new nodes. That is, temporary downtime is not supported by this
+ * class.
+ */
+public class NetworkDynamics implements Control {
+       private static final int TRACKER = 11;
+       private static final int CHOKE_TIME = 13;
+       private static final int OPTUNCHK_TIME = 14;
+       private static final int ANTISNUB_TIME = 15;
+       private static final int CHECKALIVE_TIME = 16;
+       private static final int TRACKERALIVE_TIME = 17;
+
+       /**
+        * The protocol to operate on.
+        *
+        * @config
+        */
+       private static final String PAR_PROT = "protocol";
+
+       /**
+        * Nodes are removed until the size specified by this parameter is reached.
+        * The network will never go below this size as a result of this class.
+        * Defaults to 0.
+        * 
+        * @config
+        */
+       private static final String PAR_MIN = "minsize";
+
+       /**
+        * Specifies if the tracker can disappear from the network. 0 means no, 1
+        * means yes
+        * 
+        * @config
+        */
+       private static final String PAR_TRACKER_DIE = "tracker_can_die";
+
+       /**
+        * The Transport used by the the control.
+        * 
+        * @config
+        */
+       private static final String PAR_TRANSPORT = "transport";
+
+       /**
+        * Specifies how many nodes will be added to the network.
+        * 
+        * @config
+        */
+       private static final String PAR_ADD = "add";
+
+       /**
+        * Specifies how many nodes will be removed from the network.
+        * 
+        * @config
+        */
+       private static final String PAR_REMOVE = "remove";
+
+       /*
+        * The following are local variables, obtained from config property.
+        */
+       private final int pid;
+       private final int tid;
+       private final int maxSize;
+       private final int minsize;
+       private boolean trackerCanDie = false; // false (value 0) by default
+       private final int add; // number of nodes to be added
+       private final int remove; // number of nodes to be removed
+
+       private final NodeInitializer init;
+       private Node tracker;
+
+       /**
+        * Standard constructor that reads the configuration parameters. Invoked by
+        * the simulation engine.
+        * 
+        * @param prefix
+        *            the configuration prefix for this class
+        */
+       public NetworkDynamics(String prefix) {
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);
+               minsize = Configuration.getInt(prefix + "." + PAR_MIN, 0);
+               tid = Configuration.getPid(prefix + "." + PAR_TRANSPORT);
+               add = Configuration.getInt(prefix + "." + PAR_ADD);
+               remove = Configuration.getInt(prefix + "." + PAR_REMOVE);
+
+               /*
+                * By default, the tracker can not disappear. If
+                * control.dynamics.tracker_can_die is set to 1, the tracker can die.
+                */
+               if (Configuration.getInt(prefix + "." + PAR_TRACKER_DIE) == 1) {
+                       trackerCanDie = true;
+               }
+
+               init = new NodeInitializer("init.net");
+               tracker = Network.get(0);
+
+               maxSize = (Network.size() - 1)
+                               + ((BitTorrent) tracker.getProtocol(pid)).maxGrowth;
+       }
+
+       /**
+        * Adds n nodes to the network. New nodes can be added only if the tracker
+        * is up.
+        * 
+        * @param n
+        *            the number of nodes to add, must be non-negative.
+        */
+       protected void add(int n) {
+               if (n == 0)
+                       return;
+               // tracker is up
+               if (tracker.isUp()) {
+                       for (int i = 0; i < n; ++i) {
+                               // create a new node
+                               Node nodeToBeAdded = (Node) Network.prototype.clone();
+
+                               // add the new node to the network
+                               Network.add(nodeToBeAdded); // questo nodo sara' in posizione
+                                                                                       // Network.len -1
+
+                               /*
+                                * Initialize the new node using the NodeInitializer class; this
+                                * it the same as
+                                * init.initialize(Network.get(Network.size()-1));
+                                */
+                               init.initialize(nodeToBeAdded);
+
+                               /*
+                                * The new node sends a TRACKER message to the tracker, asking
+                                * for a list of peers. The tracker will respond with a PEERSET
+                                * message. All the related events are also attached to the new
+                                * node.
+                                */
+                               long latency =((Transport)nodeToBeAdded.getProtocol(tid)).getLatency(nodeToBeAdded,tracker);
+                               Object ev = new SimpleMsg(TRACKER, nodeToBeAdded);
+                               EDSimulator.add(latency,ev,tracker,pid);
+//                             ((Transport) nodeToBeAdded.getProtocol(tid)).send(
+//                                             nodeToBeAdded, tracker, ev, pid);
+
+                               ev = new SimpleEvent(CHOKE_TIME);
+                               EDSimulator.add(10000, ev, nodeToBeAdded, pid);
+                               ev = new SimpleEvent(OPTUNCHK_TIME);
+                               EDSimulator.add(30000, ev, nodeToBeAdded, pid);
+                               ev = new SimpleEvent(ANTISNUB_TIME);
+                               EDSimulator.add(60000, ev, nodeToBeAdded, pid);
+                               ev = new SimpleEvent(CHECKALIVE_TIME);
+                               EDSimulator.add(120000, ev, nodeToBeAdded, pid);
+                               ev = new SimpleEvent(TRACKERALIVE_TIME);
+                               EDSimulator.add(1800000, ev, nodeToBeAdded, pid);
+
+                               // add the new node to the tracker's cache
+                               if (((BitTorrent) tracker.getProtocol(pid))
+                                               .addNeighbor(nodeToBeAdded))
+                                       System.out
+                                                       .println("DYN: A new node has been added to the network.");
+                       }
+               }
+               /*
+                * Otherwise, the tracker is down and no new nodes can be added to the
+                * network.
+                */
+               else
+                       System.out.println("DYN: Tracker is down. No new nodes added.");
+       }
+
+       /**
+        * Removes n nodes from the network. A node can be removed either if the
+        * tracker is up or down; if the tracker is up, the node to be removed will
+        * be removed also from the tracker's cache.
+        *
+        * @param n
+        *            the number of nodes to remove.
+        */
+       protected void remove(int n) {
+               // the index of the node to be removed
+               int nodeIndex = 0;
+
+               for (int i = 0; i < n; ++i) {
+                       nodeIndex = CommonState.r.nextInt(Network.size());
+                       // if the tracker can not disappear from the network
+                       if (!trackerCanDie) {
+                               /*
+                                * Choose an index for the node to be removed. The value 0 will
+                                * be discarded, since the tracker cannot disappear. Non
+                                * existing nodes cannot be removed: if the returned index
+                                * corresponds to a non-existing node, a new index will be
+                                * generated.
+                                */
+                               while (nodeIndex == 0) {
+                                       nodeIndex = CommonState.r.nextInt(Network.size());
+                               }
+                       }
+                       // otherwise, also the tracker can disappear
+                       else {
+                               nodeIndex = CommonState.r.nextInt(Network.size());
+                       }
+
+                       // a warning message
+                       // if (nodeIndex==0)
+                       // System.out.println("DYN: The tracker is going to disapper.");
+
+                       // remove the node with the given index from the network
+                       Node nodeToBeRemoved = Network.remove(nodeIndex);
+
+                       // then remove it from the tracker's cache, if it is possible (= the
+                       // tracker is up);
+                       if (tracker.isUp()) {
+                               if (((BitTorrent) tracker.getProtocol(pid))
+                                               .removeNeighbor(nodeToBeRemoved))
+                                       System.err
+                                                       .println("DYN: A node has been removed from the network.");
+                       } else { // the tracker is down
+                               System.err.println("DYN: The tracker is DOWN!");
+                       }
+               }
+       }
+
+       /**
+        * Calls {@link #add(int)} or {@link #remove} with the parameters defined by
+        * the configuration.
+        * 
+        * @return always false
+        */
+       public boolean execute() {
+               int choice = (CommonState.r.nextInt(2)); // 0 or 1
+               // adding new nodes
+               if (choice == 0) {
+                       /*
+                        * If the specified number of nodes cannot be added, it tries to add
+                        * a less number of nodes without going out of bounds. Otherwise,
+                        * all specified nodes will be added.
+                        */
+                       if (Network.size() + this.add > maxSize) {
+                               System.err.println("DYN: " + (maxSize - Network.size())
+                                               + " nodes will be added.");
+                               add(maxSize - Network.size());
+                       } else {
+                               System.err
+                                               .println("DYN: " + this.add + " nodes will be added.");
+                               add(this.add);
+                       }
+               }
+               // removing existing nodes
+               else {
+                       if (Network.size() - this.remove < minsize) {
+                               System.err.println("DYN: " + (Network.size() - minsize)
+                                               + " nodes will be removed.");
+                               remove(Network.size() - minsize);
+                       } else {
+                               System.err.println("DYN: " + this.remove
+                                               + " nodes will be removed.");
+                               remove(this.remove);
+                       }
+               }
+               return false;
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/bittorrent/NetworkInitializer.java b/contrib/psg/src/example/bittorrent/NetworkInitializer.java
new file mode 100644 (file)
index 0000000..4b5ba72
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --
+ *
+ * Please send your questions/suggestions to:
+ * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it
+ *
+ */
+
+package example.bittorrent;
+
+import peersim.core.*;
+import peersim.config.Configuration;
+import peersim.edsim.EDSimulator;
+import peersim.transport.Transport;
+import java.util.Random;
+
+/**
+ * This {@link Control} ...
+ */
+public class NetworkInitializer implements Control {
+       /**
+       * The protocol to operate on.
+       *
+       * @config
+       */
+       private static final String PAR_PROT="protocol";
+               
+       private static final String PAR_TRANSPORT="transport";
+       
+       private static final int TRACKER = 11;
+       
+       private static final int CHOKE_TIME = 13;
+       
+       private static final int OPTUNCHK_TIME = 14;
+       
+       private static final int ANTISNUB_TIME = 15;
+       
+       private static final int CHECKALIVE_TIME = 16;
+       
+       private static final int TRACKERALIVE_TIME = 17;
+       
+       /** Protocol identifier, obtained from config property */
+       private final int pid;
+       private final int tid;
+       private NodeInitializer init;
+       
+       private Random rnd;
+       
+       public NetworkInitializer(String prefix) {
+               pid = Configuration.getPid(prefix+"."+PAR_PROT);
+               tid = Configuration.getPid(prefix+"."+PAR_TRANSPORT);
+               init = new NodeInitializer(prefix);
+       }
+       
+       public boolean execute() {
+               int completed;
+               Node tracker = Network.get(0);
+               
+               // manca l'inizializzazione del tracker;
+               
+               ((BitTorrent)Network.get(0).getProtocol(pid)).initializeTracker();
+               
+               for(int i=1; i<Network.size(); i++){
+                       System.err.println("chiamate ad addNeighbor " + i);
+                       ((BitTorrent)Network.get(0).getProtocol(pid)).addNeighbor(Network.get(i));
+                       init.initialize(Network.get(i));
+               }
+               for(int i=1; i< Network.size(); i++){
+                       Node n = Network.get(i);
+                       
+                       Object ev = new SimpleMsg(TRACKER, n);
+                       long latency = ((Transport)n.getProtocol(tid)).getLatency(n,tracker);
+                       EDSimulator.add(latency,ev,tracker,pid);                        
+//                     ((Transport) n.getProtocol(tid)).send(n,tracker, ev, pid);
+
+                       ev = new SimpleEvent(CHOKE_TIME);
+                       EDSimulator.add(10000,ev,n,pid);
+                       ev = new SimpleEvent(OPTUNCHK_TIME);
+                       EDSimulator.add(30000,ev,n,pid);
+                       ev = new SimpleEvent(ANTISNUB_TIME);
+                       EDSimulator.add(60000,ev,n,pid);
+                       ev = new SimpleEvent(CHECKALIVE_TIME);
+                       EDSimulator.add(120000,ev,n,pid);
+                       ev = new SimpleEvent(TRACKERALIVE_TIME);
+                       EDSimulator.add(1800000,ev,n,pid);
+               }
+               return true;
+       }
+       
+       }
diff --git a/contrib/psg/src/example/bittorrent/NodeInitializer.java b/contrib/psg/src/example/bittorrent/NodeInitializer.java
new file mode 100644 (file)
index 0000000..df71688
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --
+ *
+ * Please send your questions/suggestions to:
+ * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it
+ *
+ */
+
+package example.bittorrent;
+
+import peersim.core.*;
+import peersim.config.Configuration;
+
+/**
+ *     This class provides a way to initialize a single node of the network.
+ *     The initialization is performed by choosing the bandwidth of the node
+ *     and choosing how much the shared file has been downloaded.
+ */
+public class NodeInitializer{
+       
+       /**
+        *      The protocol to operate on.
+        *      @config
+        */
+       private static final String PAR_PROT="protocol";
+       
+       /**
+        *      The percentage of nodes with no downloaded pieces.
+        *      @config
+        *      @see "The documentation for an example on how to properly set this parameter."
+        */
+       private static final String PAR_NEWER_DISTR="newer_distr";
+       
+       /**
+        *      The percentage of seeders in the network.
+        *      @config
+        */
+       private static final String PAR_SEEDER_DISTR="seeder_distr";
+
+       /**
+        *      The percentage of nodes with no downloaded pieces,
+        *      as defined in {@see #PAR_NEWER_DISTR}.
+        */
+       private int newerDistr;
+       
+       /**
+        *      The percentage of seeder nodes,
+        *      as defined in {@see #PAR_SEEDER_DISTR}.
+        */
+       private int seederDistr;
+       
+       /**
+        *      The BitTorrent protocol ID.
+        */     
+       private final int pid;
+       
+       /**
+        *      The basic constructor of the class, which reads the parameters
+        *      from the configuration file.
+        *      @param prefix the configuration prefix for this class
+        */
+       public NodeInitializer(String prefix){
+               pid = Configuration.getPid(prefix+"."+PAR_PROT);
+               newerDistr = Configuration.getInt(prefix+"."+PAR_NEWER_DISTR);
+               seederDistr = Configuration.getInt(prefix+"."+PAR_SEEDER_DISTR);
+       }
+       
+       /**
+        *      Initializes the node <tt>n</tt> associating it
+        *      with the BitTorrent protocol and setting the reference to the tracker,
+        *      the status of the file and the bandwidth.
+        *      @param n The node to initialize
+        */
+       public void initialize(Node n){
+               Node tracker = Network.get(0);
+               BitTorrent p;
+               p = (BitTorrent)n.getProtocol(pid);
+               p.setTracker(tracker);
+               p.setThisNodeID(n.getID());
+               setFileStatus(p);
+               setBandwidth(p);
+       }
+
+       /**
+        *      Sets the status of the shared file according to the
+        *      probability value given by {@link #getProbability()}.
+        *      @param p The BitTorrent protocol
+        */
+       private void setFileStatus(BitTorrent p){
+               int percentage = getProbability();
+               choosePieces(percentage, p);
+       }
+       
+       /**
+        *      Set the maximum bandwidth for the node, choosing
+        *      uniformly at random among 4 values.
+        *      <p>
+        *      The allowed bandwidth speed are 640 Kbps, 1 Mbps, 2 Mbps and 4 Mbps.
+        *      </p>
+        *      @param p The BitTorrent protocol
+        */
+       private void setBandwidth(BitTorrent p){
+               int value = CommonState.r.nextInt(4);
+               switch(value){
+                       case 0: p.setBandwidth(640);break; //640Kbps
+                       case 1: p.setBandwidth(1024);break;// 1Mbps
+                       case 2: p.setBandwidth(2048);break;// 2Mbps
+                       case 3: p.setBandwidth(4096);break; //4Mbps
+               }
+       }
+       
+       /**
+        *      Sets the completed pieces for the given protocol <tt>p</tt>.
+        *      @parm percentage The percentage of the downloaded pieces, according to {@link #getProbability()}
+        *      @param p the BitTorrent protocol
+        */
+       private void choosePieces(int percentage, BitTorrent p){
+               double temp = ((double)p.nPieces/100.0)*percentage; // We use a double to avoid the loss of precision
+                                                                                                // during the division operation
+               int completed = (int)temp; //integer number of piece to set as completed
+                                                         //0 if the peer is a newer
+               p.setCompleted(completed);
+               if(percentage == 100)
+                       p.setPeerStatus(1);
+               int tmp;
+               while(completed!=0){
+                       tmp = CommonState.r.nextInt(p.nPieces);
+                       if(p.getStatus(tmp)!=16){
+                               p.setStatus(tmp, 16);
+                               completed--;
+                       }
+               }
+       }
+       
+       /**
+        *      Gets a probability according with the parameter <tt>newer_distr</tt>
+        *      defined in the configuration file.
+        *      @return the probabilty value, where 0 means that the peer is new and no pieces has been downloaded,
+        *                      100 means that the peer is a seeder; other values defines a random probability.
+        *      @see #PAR_NEWER_DISTR
+        */
+       private int getProbability(){
+               int value = CommonState.r.nextInt(100);
+               if((value+1)<=seederDistr)
+                       return 100;
+               value = CommonState.r.nextInt(100);
+               if((value+1)<=newerDistr){
+                       return 0; // A newer peer, with probability newer_distr
+               }
+               else{
+                       value = CommonState.r.nextInt(9);
+                       return (value+1)*10;
+               }
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/bittorrent/PeerSetMsg.java b/contrib/psg/src/example/bittorrent/PeerSetMsg.java
new file mode 100644 (file)
index 0000000..d0e92d5
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --
+ *
+ * Please send your questions/suggestions to:
+ * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it
+ *
+ */
+package example.bittorrent;
+
+import peersim.core.*;
+
+/**
+ *     This class is a {@link SimpleMsg} and represents the <tt>peerset</tt>
+ *     message used by the tracker to send to the peers a list of neighbors.
+ */
+public class PeerSetMsg extends SimpleMsg{
+       
+       /**
+        *      The set of "friends" peers sent by the tracker to each node.
+        */
+       private Neighbor[] peerSet;
+       
+       /**
+        *      Initializes a new <tt>peerset</tt> message.
+        *      @param type is the type of the message (it should be 12)
+        *      @param array is the array containing the references to the neighbor nodes
+        *      @param sender the sender node
+        *      @see SimpleEvent
+        */
+       public PeerSetMsg(int type, Neighbor []array, Node sender){
+               super.type = type;
+               peerSet = array; // references to the effective nodes
+               super.sender = sender;
+       }
+       
+       /**
+        *      Gets the peer set.
+        *      @return the peer set, namely the set of neighbor nodes.
+        */
+       public Neighbor[] getPeerSet(){
+               return this.peerSet;    
+       }
+}
diff --git a/contrib/psg/src/example/bittorrent/SimpleEvent.java b/contrib/psg/src/example/bittorrent/SimpleEvent.java
new file mode 100644 (file)
index 0000000..1da537a
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --
+ *
+ * Please send your questions/suggestions to:
+ * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it
+ *
+ */
+
+package example.bittorrent;
+
+/**
+ * This class defines a simple event. A simple event is characterized only
+ * by its type.
+ */
+public class SimpleEvent {
+       
+       /**
+       * The identifier of the type of the event.
+       * <p>
+       * The available identifiers for event type are:<br/>
+       * <ul>
+       *  <li>1 is KEEP_ALIVE message</li>
+       *  <li>2 is CHOKE message</li>
+       *  <li>3 is UNCHOKE message</li>
+       *  <li>4 is INTERESTED message</li>
+       *  <li>5 is NOT_INTERESTED message</li>
+       *  <li>6 is HAVE message</li>
+       *  <li>7 is BITFIELD message</li>
+       *  <li>8 is REQUEST message</li>
+       *  <li>9 is PIECE message</li>
+       *  <li>10 is CANCEL message</li>
+       *  <li>11 is TRACKER message</li>
+       *  <li>12 is PEERSET message</li>
+       *  <li>13 is CHOKE_TIME event</li>
+       *  <li>14 is OPTUNCHK_TIME event</li>
+       *  <li>15 is ANTISNUB_TIME event</li>
+       *  <li>16 is CHECKALIVE_TIME event</li>
+       *  <li>17 is TRACKERALIVE_TIME event</li>
+       *  <li>18 is DOWNLOAD_COMPLETED event</li>
+       *</ul></p>
+       */
+       protected int type;
+       
+       public SimpleEvent(){
+       }
+       
+       /**
+     * Initializes the type of the event.
+        * @param type The identifier of the type of the event
+        */
+       public SimpleEvent(int type){
+               this.type = type;
+       }
+       
+       /**
+        * Gets the type of the event.
+        * @return The type of the current event.
+        */
+       public int getType(){
+               return this.type;       
+       }
+}
+
+
diff --git a/contrib/psg/src/example/bittorrent/SimpleMsg.java b/contrib/psg/src/example/bittorrent/SimpleMsg.java
new file mode 100644 (file)
index 0000000..cf9436e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --
+ *
+ * Please send your questions/suggestions to:
+ * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it
+ *
+ */
+
+package example.bittorrent;
+
+import peersim.core.*;
+
+/**
+ * This class defines a simple message.
+ * A simple message has its type and the reference of the sender node.
+ * @see SimpleEvent
+ */
+public class SimpleMsg extends SimpleEvent {
+       
+       /**
+       * The sender of the message.
+       */
+       protected Node sender;
+       
+       public SimpleMsg(){
+       }
+       
+       /**
+        * Initializes the simple message with its type and sender.
+        * @param type The identifier of the type of the message
+        * @param sender The sender of the message
+        */
+       public SimpleMsg(int type, Node sender){
+               super.type = type;
+               this.sender = sender;
+       }
+       
+       /**
+     * Gets the sender of the message.
+        * @return The sender of the message.
+        */
+       public Node getSender(){
+               return this.sender;     
+       }
+}
diff --git a/contrib/psg/src/example/chord/ChordInitializer.java b/contrib/psg/src/example/chord/ChordInitializer.java
new file mode 100644 (file)
index 0000000..799b0d7
--- /dev/null
@@ -0,0 +1,72 @@
+package example.chord;\r
+\r
+import java.math.BigInteger;\r
+import java.util.Random;\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+import peersim.dynamics.NodeInitializer;\r
+\r
+public class ChordInitializer implements NodeInitializer {\r
+\r
+       private static final String PAR_PROT = "protocol";\r
+\r
+       private int pid = 0;\r
+\r
+       private ChordProtocol cp;\r
+\r
+       public ChordInitializer(String prefix) {\r
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);\r
+       }\r
+\r
+       public void initialize(Node n) {\r
+               cp = (ChordProtocol) n.getProtocol(pid);\r
+               join(n);\r
+       }\r
+\r
+       public void join(Node myNode) {\r
+               Random generator = new Random();\r
+               //Random generator = new Random(1234567890);\r
+               cp.predecessor = null;\r
+               // search a node to join\r
+               Node n;\r
+               do {\r
+                       n = Network.get(generator.nextInt(Network.size()));\r
+               } while (n == null || n.isUp() == false);\r
+               cp.m = ((ChordProtocol) n.getProtocol(pid)).m;\r
+               cp.chordId = new BigInteger(cp.m, CommonState.r);\r
+               ChordProtocol cpRemote = (ChordProtocol) n.getProtocol(pid);\r
+\r
+               Node successor = cpRemote.find_successor(cp.chordId);\r
+               cp.fails = 0;\r
+               cp.stabilizations = 0;\r
+               cp.varSuccList = cpRemote.varSuccList;\r
+               cp.varSuccList = 0;\r
+               cp.succLSize = cpRemote.succLSize;\r
+               cp.successorList = new Node[cp.succLSize];\r
+               cp.successorList[0] = successor;\r
+               cp.fingerTable = new Node[cp.m];\r
+               long succId = 0;\r
+               BigInteger lastId = ((ChordProtocol) Network.get(Network.size() - 1)\r
+                               .getProtocol(pid)).chordId;\r
+               do {\r
+                       cp.stabilizations++;\r
+                       succId = cp.successorList[0].getID();\r
+                       cp.stabilize(myNode);\r
+                       if (((ChordProtocol) cp.successorList[0].getProtocol(pid)).chordId\r
+                                       .compareTo(cp.chordId) < 0) {\r
+                               cp.successorList[0] = ((ChordProtocol) cp.successorList[0]\r
+                                               .getProtocol(pid)).find_successor(cp.chordId);\r
+                       }\r
+                       // controllo di non essere l'ultimo elemento della rete\r
+                       if (cp.chordId.compareTo(lastId) > 0) {\r
+                               cp.successorList[0] = Network.get(0);\r
+                               break;\r
+                       }\r
+               } while (cp.successorList[0].getID() != succId\r
+                               || ((ChordProtocol) cp.successorList[0].getProtocol(pid)).chordId\r
+                                               .compareTo(cp.chordId) < 0);\r
+               cp.fixFingers();\r
+       }\r
+}\r
diff --git a/contrib/psg/src/example/chord/ChordMessage.java b/contrib/psg/src/example/chord/ChordMessage.java
new file mode 100644 (file)
index 0000000..f87fafb
--- /dev/null
@@ -0,0 +1,12 @@
+/**\r
+ * \r
+ */\r
+package example.chord;\r
+\r
+/**\r
+ * @author Andrea\r
+ * \r
+ */\r
+public interface ChordMessage {\r
+\r
+}\r
diff --git a/contrib/psg/src/example/chord/ChordProtocol.java b/contrib/psg/src/example/chord/ChordProtocol.java
new file mode 100644 (file)
index 0000000..485c3ba
--- /dev/null
@@ -0,0 +1,358 @@
+/**\r
+ * \r
+ */\r
+package example.chord;\r
+\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+import peersim.edsim.EDProtocol;\r
+import peersim.transport.Transport;\r
+\r
+import java.math.*;\r
+\r
+import org.simgrid.msg.Host;\r
+import org.simgrid.msg.Msg;\r
+\r
+/**\r
+ * @author Andrea\r
+ * \r
+ */\r
+public class ChordProtocol implements EDProtocol {\r
+\r
+       private static final String PAR_TRANSPORT = "transport";\r
+\r
+       private Parameters p;\r
+\r
+       private int[] lookupMessage;\r
+\r
+       public int index = 0;\r
+\r
+       public Node predecessor;\r
+\r
+       public Node[] fingerTable;\r
+\r
+       public Node[] successorList;\r
+\r
+       public BigInteger chordId;\r
+\r
+       public int m;\r
+\r
+       public int succLSize;\r
+\r
+       public String prefix;\r
+\r
+       private int next = 0;\r
+\r
+       // campo x debug\r
+       private int currentNode = 0;\r
+\r
+       public int varSuccList = 0;\r
+\r
+       public int stabilizations = 0;\r
+\r
+       public int fails = 0;\r
+\r
+       /**\r
+        * \r
+        */\r
+       public ChordProtocol(String prefix) {\r
+               this.prefix = prefix;\r
+               lookupMessage = new int[1];\r
+               lookupMessage[0] = 0;\r
+               p = new Parameters();\r
+               p.tid = Configuration.getPid(prefix + "." + PAR_TRANSPORT);\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * \r
+        * @see peersim.edsim.EDProtocol#processEvent(peersim.core.Node, int,\r
+        * java.lang.Object)\r
+        */\r
+       public void processEvent(Node node, int pid, Object event) {\r
+               // processare le richieste a seconda della routing table del nodo\r
+               p.pid = pid;\r
+               // currentNode = node.getIndex();\r
+               currentNode = (int) node.getID();\r
+               if (event.getClass() == LookUpMessage.class) {\r
+                       LookUpMessage message = (LookUpMessage) event;\r
+                       message.increaseHopCounter();\r
+                       BigInteger target = message.getTarget();\r
+                       Transport t = (Transport) node.getProtocol(p.tid);\r
+                       Node n = message.getSender();\r
+                       System.out.println("R process " + "at time="\r
+                                       + CommonState.getTime() + " to dest:" + currentNode\r
+                                       + " from src:" + n.getID() + " message: ("\r
+                                       + message.getSender().getID() + ";" + message.getTarget()\r
+                                       + ")");\r
+                       if (target == ((ChordProtocol) node.getProtocol(pid)).chordId) {\r
+                               // mandare mess di tipo final\r
+                               Object msg = new FinalMessage(message.getHopCounter());\r
+                               System.out.println("S Final Message " + "at time="\r
+                                               + CommonState.getTime() + " from src:" + node.getID()\r
+                                               + " to dest:" + n.getID() + " message: "\r
+                                               + message.getHopCounter() + " HopCounter");\r
+                               t.send(node, n, msg, pid);\r
+\r
+                       }\r
+                       if (target != ((ChordProtocol) node.getProtocol(pid)).chordId) {\r
+                               // funzione lookup sulla fingertabable\r
+                               Node dest = find_successor(target);\r
+                               if (dest.isUp() == false) {\r
+                                       do {\r
+                                               varSuccList = 0;\r
+                                               stabilize(node);\r
+                                               stabilizations++;\r
+                                               fixFingers();\r
+                                               dest = find_successor(target);\r
+                                       } while (dest.isUp() == false);\r
+                               }\r
+                               if (dest.getID() == successorList[0].getID()\r
+                                               && (target.compareTo(((ChordProtocol) dest\r
+                                                               .getProtocol(p.pid)).chordId) < 0)) {\r
+                                       fails++;\r
+                               } else {\r
+                                       System.out.println("S process " + "at time="\r
+                                                       + CommonState.getTime() + " from src:"\r
+                                                       + node.getID() + " to dest:" + dest.getID()\r
+                                                       + " message: (" + message.getSender().getID() + ";"\r
+                                                       + message.getTarget() + ")");\r
+                                       // t.send(message.getSender(), dest, message, pid);\r
+                                       t.send(node, dest, message, pid);\r
+\r
+                               }\r
+                       }\r
+               }\r
+               if (event.getClass() == FinalMessage.class) {\r
+                       FinalMessage message = (FinalMessage) event;\r
+                       System.out.println("R Final Message " + "at time="\r
+                                       + CommonState.getTime() + " to dest:" + node.getID()+"\n");\r
+                       lookupMessage = new int[index + 1];\r
+                       lookupMessage[index] = message.getHopCounter();\r
+                       index++;\r
+               }\r
+       }\r
+\r
+       public Object clone() {\r
+               ChordProtocol cp = new ChordProtocol(prefix);\r
+               String val = BigInteger.ZERO.toString();\r
+               cp.chordId = new BigInteger(val);\r
+               cp.fingerTable = new Node[m];\r
+               cp.successorList = new Node[succLSize];\r
+               cp.currentNode = 0;\r
+               return cp;\r
+       }\r
+\r
+       public int[] getLookupMessage() {\r
+               return lookupMessage;\r
+       }\r
+\r
+       public void stabilize(Node myNode) {\r
+               try {\r
+                       Node node = ((ChordProtocol) successorList[0].getProtocol(p.pid)).predecessor;\r
+                       if (node != null) {\r
+                               if (this.chordId == ((ChordProtocol) node.getProtocol(p.pid)).chordId)\r
+                                       return;\r
+                               BigInteger remoteID = ((ChordProtocol) node.getProtocol(p.pid)).chordId;\r
+                               if (idInab(\r
+                                               remoteID,\r
+                                               chordId,\r
+                                               ((ChordProtocol) successorList[0].getProtocol(p.pid)).chordId))\r
+                                       successorList[0] = node;\r
+                               ((ChordProtocol) successorList[0].getProtocol(p.pid))\r
+                                               .notify(myNode);\r
+                       }\r
+                       updateSuccessorList();\r
+               } catch (Exception e1) {\r
+                       e1.printStackTrace();\r
+                       updateSuccessor();\r
+               }\r
+       }\r
+\r
+       private void updateSuccessorList() throws Exception {\r
+               try {\r
+                       while (successorList[0] == null || successorList[0].isUp() == false) {\r
+                               updateSuccessor();\r
+                       }\r
+                       System.arraycopy(\r
+                                       ((ChordProtocol) successorList[0].getProtocol(p.pid)).successorList,\r
+                                       0, successorList, 1, succLSize - 2);\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+\r
+       public void notify(Node node) throws Exception {\r
+               BigInteger nodeId = ((ChordProtocol) node.getProtocol(p.pid)).chordId;\r
+               if ((predecessor == null)\r
+                               || (idInab(\r
+                                               nodeId,\r
+                                               ((ChordProtocol) predecessor.getProtocol(p.pid)).chordId,\r
+                                               this.chordId))) {\r
+                       predecessor = node;\r
+               }\r
+       }\r
+\r
+       private void updateSuccessor() {\r
+               boolean searching = true;\r
+               while (searching) {\r
+                       try {\r
+                               Node node = successorList[varSuccList];\r
+                               varSuccList++;\r
+                               successorList[0] = node;\r
+                               if (successorList[0] == null\r
+                                               || successorList[0].isUp() == false) {\r
+                                       if (varSuccList >= succLSize - 1) {\r
+                                               searching = false;\r
+                                               varSuccList = 0;\r
+                                       } else\r
+                                               updateSuccessor();\r
+                               }\r
+                               updateSuccessorList();\r
+                               searching = false;\r
+                       } catch (Exception e) {\r
+                               e.printStackTrace();\r
+                       }\r
+               }\r
+       }\r
+\r
+       private boolean idInab(BigInteger id, BigInteger a, BigInteger b) {\r
+               if ((a.compareTo(id) == -1) && (id.compareTo(b) == -1)) {\r
+                       return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       public Node find_successor(BigInteger id) {\r
+               try {\r
+                       if (successorList[0] == null || successorList[0].isUp() == false) {\r
+                               updateSuccessor();\r
+                       }\r
+                       if (idInab(\r
+                                       id,\r
+                                       this.chordId,\r
+                                       ((ChordProtocol) successorList[0].getProtocol(p.pid)).chordId)) {\r
+                               return successorList[0];\r
+                       } else {\r
+                               Node tmp = closest_preceding_node(id);\r
+                               return tmp;\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+               return successorList[0];\r
+       }\r
+\r
+       private Node closest_preceding_node(BigInteger id) {\r
+               for (int i = m; i > 0; i--) {\r
+                       try {\r
+                               if (fingerTable[i - 1] == null\r
+                                               || fingerTable[i - 1].isUp() == false) {\r
+                                       continue;\r
+                               }\r
+                               BigInteger fingerId = ((ChordProtocol) (fingerTable[i - 1]\r
+                                               .getProtocol(p.pid))).chordId;\r
+                               if ((idInab(fingerId, this.chordId, id))\r
+                                               || (id.compareTo(fingerId) == 0)) {\r
+                                       return fingerTable[i - 1];\r
+                               }\r
+                               if (fingerId.compareTo(this.chordId) == -1) {\r
+                                       // sono nel caso in cui ho fatto un giro della rete\r
+                                       // circolare\r
+                                       if (idInab(id, fingerId, this.chordId)) {\r
+                                               return fingerTable[i - 1];\r
+                                       }\r
+                               }\r
+                               if ((id.compareTo(fingerId) == -1)\r
+                                               && (id.compareTo(this.chordId) == -1)) {\r
+                                       if (i == 1)\r
+                                               return successorList[0];\r
+                                       BigInteger lowId = ((ChordProtocol) fingerTable[i - 2]\r
+                                                       .getProtocol(p.pid)).chordId;\r
+                                       if (idInab(id, lowId, fingerId))\r
+                                               return fingerTable[i - 2];\r
+                                       else if (fingerId.compareTo(this.chordId) == -1)\r
+                                               continue;\r
+                                       else if (fingerId.compareTo(this.chordId) == 1)\r
+                                               return fingerTable[i - 1];\r
+                               }\r
+                       } catch (Exception e) {\r
+                               e.printStackTrace();\r
+                       }\r
+               }\r
+               if (fingerTable[m - 1] == null)\r
+                       return successorList[0];\r
+               return successorList[0];\r
+       }\r
+\r
+       // debug function\r
+       private void printFingers() {\r
+               for (int i = fingerTable.length - 1; i > 0; i--) {\r
+                       if (fingerTable[i] == null) {\r
+                               System.out.println("Finger " + i + " is null");\r
+                               continue;\r
+                       }\r
+                       if ((((ChordProtocol) fingerTable[i].getProtocol(p.pid)).chordId)\r
+                                       .compareTo(this.chordId) == 0)\r
+                               break;\r
+                       System.out\r
+                                       .println("Finger["\r
+                                                       + i\r
+                                                       + "] = "\r
+                                                       + fingerTable[i].getIndex()\r
+                                                       + " chordId "\r
+                                                       + ((ChordProtocol) fingerTable[i]\r
+                                                                       .getProtocol(p.pid)).chordId);\r
+               }\r
+       }\r
+\r
+       public void fixFingers() {\r
+               if (next >= m - 1)\r
+                       next = 0;\r
+               if (fingerTable[next] != null && fingerTable[next].isUp()) {\r
+                       next++;\r
+                       return;\r
+               }\r
+               BigInteger base;\r
+               if (next == 0)\r
+                       base = BigInteger.ONE;\r
+               else {\r
+                       base = BigInteger.valueOf(2);\r
+                       for (int exp = 1; exp < next; exp++) {\r
+                               base = base.multiply(BigInteger.valueOf(2));\r
+                       }\r
+               }\r
+               BigInteger pot = this.chordId.add(base);\r
+               BigInteger idFirst = ((ChordProtocol) Network.get(0).getProtocol(p.pid)).chordId;\r
+               BigInteger idLast = ((ChordProtocol) Network.get(Network.size() - 1)\r
+                               .getProtocol(p.pid)).chordId;\r
+               if (pot.compareTo(idLast) == 1) {\r
+                       pot = (pot.mod(idLast));\r
+                       if (pot.compareTo(this.chordId) != -1) {\r
+                               next++;\r
+                               return;\r
+                       }\r
+                       if (pot.compareTo(idFirst) == -1) {\r
+                               this.fingerTable[next] = Network.get(Network.size() - 1);\r
+                               next++;\r
+                               return;\r
+                       }\r
+               }\r
+               do {\r
+                       fingerTable[next] = ((ChordProtocol) successorList[0]\r
+                                       .getProtocol(p.pid)).find_successor(pot);\r
+                       pot = pot.subtract(BigInteger.ONE);\r
+                       ((ChordProtocol) successorList[0].getProtocol(p.pid)).fixFingers();\r
+               } while (fingerTable[next] == null || fingerTable[next].isUp() == false);\r
+               next++;\r
+       }\r
+\r
+       /**\r
+        */\r
+       public void emptyLookupMessage() {\r
+               index = 0;\r
+               this.lookupMessage = new int[0];\r
+       }\r
+}\r
diff --git a/contrib/psg/src/example/chord/CreateNw.java b/contrib/psg/src/example/chord/CreateNw.java
new file mode 100644 (file)
index 0000000..9268653
--- /dev/null
@@ -0,0 +1,148 @@
+/**\r
+ * \r
+ */\r
+package example.chord;\r
+\r
+import peersim.core.*;\r
+import peersim.config.Configuration;\r
+import java.math.*;\r
+\r
+/**\r
+ * @author Andrea\r
+ * \r
+ */\r
+public class CreateNw implements Control {\r
+\r
+       private int pid = 0;\r
+\r
+       private static final String PAR_IDLENGTH = "idLength";\r
+\r
+       private static final String PAR_PROT = "protocol";\r
+\r
+       private static final String PAR_SUCCSIZE = "succListSize";\r
+\r
+       int idLength = 0;\r
+\r
+       int successorLsize = 0;\r
+\r
+       int fingSize = 0;\r
+       //campo x debug\r
+       boolean verbose = false;\r
+\r
+       /**\r
+        * \r
+        */\r
+       public CreateNw(String prefix) {\r
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);\r
+               idLength = Configuration.getInt(prefix + "." + PAR_IDLENGTH); \r
+               successorLsize = Configuration.getInt(prefix + "." + PAR_SUCCSIZE); \r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * \r
+        * @see peersim.core.Control#execute()\r
+        */\r
+\r
+       public boolean execute() {\r
+               for (int i = 0; i < Network.size(); i++) {\r
+                       Node node = (Node) Network.get(i);\r
+                       ChordProtocol cp = (ChordProtocol) node.getProtocol(pid);\r
+                       cp.m = idLength;\r
+                       cp.succLSize = successorLsize;\r
+                       cp.varSuccList = 0;\r
+                       cp.chordId = new BigInteger(idLength, CommonState.r);\r
+                       cp.fingerTable = new Node[idLength];\r
+                       cp.successorList = new Node[successorLsize];\r
+               }\r
+               NodeComparator nc = new NodeComparator(pid);\r
+               Network.sort(nc);\r
+               createFingerTable();\r
+               return false;\r
+       }\r
+\r
+       public Node findId(BigInteger id, int nodeOne, int nodeTwo) {\r
+               if (nodeOne >= (nodeTwo - 1)) \r
+                       return Network.get(nodeOne);\r
+               int middle = (nodeOne + nodeTwo) / 2;\r
+               if (((middle) >= Network.size() - 1))\r
+                       System.out.print("ERROR: Middle is bigger than Network.size");\r
+               if (((middle) <= 0))\r
+                       return Network.get(0);\r
+               try {\r
+                       BigInteger newId = ((ChordProtocol) ((Node) Network.get(middle))\r
+                                       .getProtocol(pid)).chordId;\r
+                       BigInteger lowId;\r
+                       if (middle > 0)\r
+                               lowId = ((ChordProtocol) ((Node) Network.get(middle - 1))\r
+                                               .getProtocol(pid)).chordId;\r
+                       else\r
+                               lowId = newId;\r
+                       BigInteger highId = ((ChordProtocol) ((Node) Network\r
+                                       .get(middle + 1)).getProtocol(pid)).chordId;\r
+                       if (id.compareTo(newId) == 0\r
+                                       || ((id.compareTo(newId) == 1) && (id.compareTo(highId) == -1))) {\r
+                               return Network.get(middle);\r
+                       }\r
+                       if ((id.compareTo(newId) == -1) && (id.compareTo(lowId) == 1)) {\r
+                               if (middle > 0)\r
+                                       return Network.get(middle - 1);\r
+                               else\r
+                                       return Network.get(0);\r
+                       }\r
+                       if (id.compareTo(newId) == -1) {\r
+                               return findId(id, nodeOne, middle);\r
+                       } else if (id.compareTo(newId) == 1) {\r
+                               return findId(id, middle, nodeTwo);\r
+                       }\r
+                       return null;\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       public void createFingerTable() {\r
+               BigInteger idFirst = ((ChordProtocol) Network.get(0).getProtocol(pid)).chordId;\r
+               BigInteger idLast = ((ChordProtocol) Network.get(Network.size() - 1)\r
+                               .getProtocol(pid)).chordId;\r
+               for (int i = 0; i < Network.size(); i++) {\r
+                       Node node = (Node) Network.get(i);\r
+                       ChordProtocol cp = (ChordProtocol) node.getProtocol(pid);\r
+                       for (int a = 0; a < successorLsize; a++) {\r
+                               if (a + i < (Network.size() - 1))\r
+                                       cp.successorList[a] = Network.get(a + i + 1);\r
+                               else\r
+                                       cp.successorList[a] = Network.get(a);\r
+                       }\r
+                       if (i > 0)\r
+                               cp.predecessor = (Node) Network.get(i - 1);\r
+                       else\r
+                               cp.predecessor = (Node) Network.get(Network.size() - 1);\r
+                       int j = 0;\r
+                       for (j = 0; j < idLength; j++) {\r
+                               BigInteger base;\r
+                               if (j == 0)\r
+                                       base = BigInteger.ONE;\r
+                               else {\r
+                                       base = BigInteger.valueOf(2);\r
+                                       for (int exp = 1; exp < j; exp++) {\r
+                                               base = base.multiply(BigInteger.valueOf(2));\r
+                                       }\r
+                               }\r
+                               BigInteger pot = cp.chordId.add(base);\r
+                               if (pot.compareTo(idLast) == 1) {\r
+                                       pot = (pot.mod(idLast));\r
+                                       if (pot.compareTo(cp.chordId) != -1) {\r
+                                               break;\r
+                                       }\r
+                                       if (pot.compareTo(idFirst) == -1) {\r
+                                               cp.fingerTable[j] = Network.get(Network.size() - 1);\r
+                                               continue;\r
+                                       }\r
+                               }\r
+                               cp.fingerTable[j] = findId(pot, 0, Network.size() - 1);\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/contrib/psg/src/example/chord/FinalMessage.java b/contrib/psg/src/example/chord/FinalMessage.java
new file mode 100644 (file)
index 0000000..847dba9
--- /dev/null
@@ -0,0 +1,14 @@
+package example.chord;\r
+\r
+public class FinalMessage implements ChordMessage {\r
+\r
+       private int hopCounter = 0;\r
+\r
+       public FinalMessage(int hopCounter) {\r
+               this.hopCounter = hopCounter;\r
+       }\r
+\r
+       public int getHopCounter() {\r
+               return hopCounter;\r
+       }\r
+}\r
diff --git a/contrib/psg/src/example/chord/LookUpMessage.java b/contrib/psg/src/example/chord/LookUpMessage.java
new file mode 100644 (file)
index 0000000..091089e
--- /dev/null
@@ -0,0 +1,44 @@
+package example.chord;\r
+\r
+import java.math.*;\r
+import peersim.core.*;\r
+\r
+public class LookUpMessage implements ChordMessage {\r
+\r
+       private Node sender;\r
+\r
+       private BigInteger targetId;\r
+\r
+       private int hopCounter = -1;\r
+\r
+       public LookUpMessage(Node sender, BigInteger targetId) {\r
+               this.sender = sender;\r
+               this.targetId = targetId;\r
+       }\r
+\r
+       public void increaseHopCounter() {\r
+               hopCounter++;\r
+       }\r
+\r
+       /**\r
+        * @return the senderId\r
+        */\r
+       public Node getSender() {\r
+               return sender;\r
+       }\r
+\r
+       /**\r
+        * @return the target\r
+        */\r
+       public BigInteger getTarget() {\r
+               return targetId;\r
+       }\r
+\r
+       /**\r
+        * @return the hopCounter\r
+        */\r
+       public int getHopCounter() {\r
+               return hopCounter;\r
+       }\r
+\r
+}\r
diff --git a/contrib/psg/src/example/chord/MessageCounterObserver.java b/contrib/psg/src/example/chord/MessageCounterObserver.java
new file mode 100644 (file)
index 0000000..dbcbb8f
--- /dev/null
@@ -0,0 +1,108 @@
+/**\r
+ * \r
+ */\r
+package example.chord;\r
+\r
+import java.util.ArrayList;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.config.Configuration;\r
+\r
+/**\r
+ * @author Andrea\r
+ * \r
+ */\r
+public class MessageCounterObserver implements Control {\r
+\r
+       private static final String PAR_PROT = "protocol";\r
+\r
+       private final String prefix;\r
+\r
+       private final int pid;\r
+\r
+       /**\r
+        * \r
+        */\r
+       public MessageCounterObserver(String prefix) {\r
+               this.prefix = prefix;\r
+               this.pid = Configuration.getPid(prefix + "." + PAR_PROT);\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * \r
+        * @see peersim.core.Control#execute()\r
+        */\r
+       public boolean execute() {\r
+               int size = Network.size();\r
+               int totalStab = 0;\r
+               int totFails = 0;\r
+               ArrayList hopCounters = new ArrayList(); // struttura dati che\r
+                                                                                                       // memorizza gli hop di\r
+                                                                                                       // tutti i mess mandati\r
+               hopCounters.clear();\r
+               int max = 0;\r
+               int min = Integer.MAX_VALUE;\r
+               for (int i = 0; i < size; i++) {\r
+                       ChordProtocol cp = (ChordProtocol) Network.get(i).getProtocol(pid);\r
+                       // trovare tutti gli hopCOunter dei messaggi lookup mandati\r
+                       int[] counters = new int[cp.getLookupMessage().length];\r
+                       System.arraycopy(cp.getLookupMessage(), 0, counters, 0, cp\r
+                                       .getLookupMessage().length);\r
+                       totalStab = totalStab + cp.stabilizations;\r
+                       totFails = totFails + cp.fails;\r
+                       cp.stabilizations = 0;\r
+                       cp.fails = 0;\r
+                       int maxNew = maxArray(counters, cp.index);\r
+                       if (maxNew > max)\r
+                               max = maxNew;\r
+                       if (cp.index != 0) {\r
+                               for (int j = 0; j < cp.index; j++)\r
+                                       hopCounters.add(counters[j]);\r
+                               int minNew = minArray(counters, cp.index);\r
+                               if (minNew < min)\r
+                                       min = minNew;\r
+                       }\r
+                       cp.emptyLookupMessage();\r
+               }\r
+               double media = meanCalculator(hopCounters);\r
+               if (media > 0)\r
+                       System.out.println("Mean:  " + media + " Max Value: " + max\r
+                                       + " Min Value: " + min + " # Observations: "\r
+                                       + hopCounters.size());\r
+               System.out.println("     # Stabilizations: " + totalStab + " # Failures: "\r
+                               + totFails);\r
+               System.out.println("");\r
+               return false;\r
+       }\r
+\r
+       private double meanCalculator(ArrayList list) {\r
+               int lenght = list.size();\r
+               if (lenght == 0)\r
+                       return 0;\r
+               int sum = 0;\r
+               for (int i = 0; i < lenght; i++) {\r
+                       sum = sum + ((Integer) list.get(i)).intValue();\r
+               }\r
+               double mean = sum / lenght;\r
+               return mean;\r
+       }\r
+\r
+       private int maxArray(int[] array, int dim) {\r
+               int max = 0;\r
+               for (int j = 0; j < dim; j++) {\r
+                       if (array[j] > max)\r
+                               max = array[j];\r
+               }\r
+               return max;\r
+       }\r
+\r
+       private int minArray(int[] array, int dim) {\r
+               int min = 0;\r
+               for (int j = 0; j < dim; j++) {\r
+                       if (array[j] < min)\r
+                               min = array[j];\r
+               }\r
+               return min;\r
+       }\r
+}\r
diff --git a/contrib/psg/src/example/chord/NodeComparator.java b/contrib/psg/src/example/chord/NodeComparator.java
new file mode 100644 (file)
index 0000000..def16dc
--- /dev/null
@@ -0,0 +1,21 @@
+package example.chord;\r
+\r
+import java.util.Comparator;\r
+import java.math.*;\r
+import peersim.core.*;\r
+\r
+public class NodeComparator implements Comparator {\r
+\r
+       public int pid = 0;\r
+\r
+       public NodeComparator(int pid) {\r
+               this.pid = pid;\r
+       }\r
+\r
+       public int compare(Object arg0, Object arg1) {\r
+               BigInteger one = ((ChordProtocol) ((Node) arg0).getProtocol(pid)).chordId;\r
+               BigInteger two = ((ChordProtocol) ((Node) arg1).getProtocol(pid)).chordId;\r
+               return one.compareTo(two);\r
+       }\r
+\r
+}\r
diff --git a/contrib/psg/src/example/chord/Parameters.java b/contrib/psg/src/example/chord/Parameters.java
new file mode 100644 (file)
index 0000000..d32d82f
--- /dev/null
@@ -0,0 +1,7 @@
+package example.chord;\r
+\r
+public class Parameters {\r
+       int pid;\r
+\r
+       int tid;\r
+}\r
diff --git a/contrib/psg/src/example/chord/TrafficGenerator.java b/contrib/psg/src/example/chord/TrafficGenerator.java
new file mode 100644 (file)
index 0000000..09c5854
--- /dev/null
@@ -0,0 +1,54 @@
+/**\r
+ * \r
+ */\r
+package example.chord;\r
+\r
+import org.simgrid.msg.Host;\r
+\r
+import peersim.core.*;\r
+import peersim.config.Configuration;\r
+import peersim.edsim.EDSimulator;\r
+import psgsim.PSGSimulator;\r
+\r
+/**\r
+ * @author Andrea\r
+ * \r
+ */\r
+public class TrafficGenerator implements Control {\r
+\r
+       private static final String PAR_PROT = "protocol";\r
+\r
+       private final int pid;\r
+\r
+       /**\r
+        * \r
+        */\r
+       public TrafficGenerator(String prefix) {\r
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * \r
+        * @see peersim.core.Control#execute()\r
+        */\r
+       public boolean execute() {\r
+               int size = Network.size();\r
+               Node sender, target;\r
+               int i = 0;\r
+               do {\r
+                       i++;\r
+                       sender = Network.get(CommonState.r.nextInt(size));\r
+                       target = Network.get(CommonState.r.nextInt(size));\r
+               } while (sender == null || sender.isUp() == false || target == null\r
+                               || target.isUp() == false);\r
+               LookUpMessage message = new LookUpMessage(sender,\r
+                               ((ChordProtocol) target.getProtocol(pid)).chordId);\r
+               System.out.println("TrafficGenerator at time "+CommonState.getTime()+" Node:"\r
+                               + message.getSender().getID() +" target "+target.getID() + " pid:"\r
+                               + pid);\r
+               EDSimulator.add(10, message, sender, pid);\r
+               return false;\r
+       }\r
+\r
+}\r
diff --git a/contrib/psg/src/example/edaggregation/AverageED.java b/contrib/psg/src/example/edaggregation/AverageED.java
new file mode 100644 (file)
index 0000000..c5f3358
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2003 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package example.edaggregation;
+
+import peersim.vector.SingleValueHolder;
+import peersim.config.*;
+import peersim.core.*;
+import peersim.transport.Transport;
+import peersim.cdsim.CDProtocol;
+import peersim.edsim.EDProtocol;
+
+/**
+ * Event driven version of epidemic averaging.
+ */
+public class AverageED extends SingleValueHolder implements CDProtocol,
+               EDProtocol {
+
+       // --------------------------------------------------------------------------
+       // Initialization
+       // --------------------------------------------------------------------------
+
+       /**
+        * @param prefix
+        *            string prefix for config properties
+        */
+       public AverageED(String prefix) {
+               super(prefix);
+       }
+
+       // --------------------------------------------------------------------------
+       // methods
+       // --------------------------------------------------------------------------
+
+       /**
+        * This is the standard method the define periodic activity. The frequency
+        * of execution of this method is defined by a
+        * {@link peersim.edsim.CDScheduler} component in the configuration.
+        */
+       public void nextCycle(Node node, int pid) {
+               Linkable linkable = (Linkable) node.getProtocol(FastConfig
+                               .getLinkable(pid));
+               if (linkable.degree() > 0) {
+                       int degree=linkable.degree();
+                       int i=CommonState.r.nextInt(degree);            
+                       Node peern = linkable.getNeighbor(i);
+                       System.out.println("Pid of the protocol: "+pid);
+                       System.out.println("Time="+CommonState.getTime()+" degree="+degree+" i="+i+" peernID="+peern.getID()+" peernIndex="+peern.getIndex());
+                       if (!peern.isUp())
+                               return;
+                       AverageMessage ob=new AverageMessage(value, node);
+                       System.out.println("NextCycle\t"+"\t Time: " + CommonState.getTime()+ "\t src: " + node.getID() + "\t dst: " + peern.getID()+"\t msg:"+ob.value);
+                       ((Transport) node.getProtocol(FastConfig.getTransport(pid))).send(
+                                       node, peern, ob, pid);
+               }
+       }
+
+       // --------------------------------------------------------------------------
+
+       /**
+        * This is the standard method to define to process incoming messages.
+        */
+       public void processEvent(Node node, int pid, Object event) {
+
+               AverageMessage aem = (AverageMessage) event;
+
+               AverageMessage ob=null;
+               if (aem.sender != null){
+                       System.out.println("ProcessEventR\t"+"\t Time: " + CommonState.getTime() + "\t src: " + aem.sender.getID() + "\t dst: " + node.getID()+"\t msg:"+aem.value);
+                       ob=new AverageMessage(value, null);
+                       System.out.println("ProcessEventS\t"+"\t Time: " + CommonState.getTime()+ "\t src: " + node.getID() + "\t dst: " + aem.sender.getID()+"\t msg:"+ob.value);
+                       ((Transport) node.getProtocol(FastConfig.getTransport(pid))).send(
+                                       node, aem.sender, ob, pid);
+       } else {
+               System.out.println("ProcessEventR\t"+"\t Time: " +CommonState.getTime() + "\t src: " + "NULL" + "\t dst: " + node.getID()+"\t msg:"+aem.value);
+       }
+               value = (value + aem.value) / 2;
+       }
+
+}
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
+/**
+ * The type of a message. It contains a value of type double and the sender node
+ * of type {@link peersim.core.Node}.
+ */
+class AverageMessage {
+
+       final double value;
+       /**
+        * If not null, this has to be answered, otherwise this is the answer.
+        */
+       final Node sender;
+
+       public AverageMessage(double value, Node sender) {
+               this.value = value;
+               this.sender = sender;
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/symphony/AdapterIterableNetwork.java b/contrib/psg/src/example/symphony/AdapterIterableNetwork.java
new file mode 100644 (file)
index 0000000..37bf104
--- /dev/null
@@ -0,0 +1,31 @@
+package example.symphony;\r
+\r
+import java.util.Iterator;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ * Adapter Class absolutely UNSAFE, just to be able to iterate peersim.core.Network\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class AdapterIterableNetwork implements Iterable<Node>, Iterator<Node> {\r
+\r
+    private int i = 0;\r
+\r
+    public Iterator<Node> iterator() {\r
+        return this;\r
+    }\r
+\r
+    public boolean hasNext() {\r
+        return i < Network.size();\r
+    }\r
+\r
+    public Node next() {\r
+        return Network.get(i++);\r
+    }\r
+\r
+    public void remove() {\r
+        throw new UnsupportedOperationException("Not supported yet.");\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/AdapterSymphonyNodeComparator.java b/contrib/psg/src/example/symphony/AdapterSymphonyNodeComparator.java
new file mode 100644 (file)
index 0000000..b05bbb6
--- /dev/null
@@ -0,0 +1,28 @@
+package example.symphony;\r
+\r
+import java.util.Comparator;\r
+\r
+import example.symphony.SymphonyProtocol.BootstrapStatus;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ * Object-Adapter\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class AdapterSymphonyNodeComparator implements Comparator<Tuple<Node, BootstrapStatus>> {\r
+\r
+    private SymphonyNodeComparator comparator;\r
+\r
+    public AdapterSymphonyNodeComparator(SymphonyNodeComparator comparator) {\r
+        this.comparator = comparator;\r
+    }\r
+\r
+    public int compare(Tuple<Node, BootstrapStatus> o1, Tuple<Node, BootstrapStatus> o2) {\r
+\r
+        Node node1 = o1.x;\r
+        Node node2 = o2.x;\r
+\r
+        return comparator.compare(node1, node2);\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/Handler.java b/contrib/psg/src/example/symphony/Handler.java
new file mode 100644 (file)
index 0000000..c78d774
--- /dev/null
@@ -0,0 +1,19 @@
+package example.symphony;\r
+\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public interface Handler {\r
+\r
+    /**\r
+     * Handler associable to a routing request\r
+     *\r
+     * @param src Symphony Protocol that has sent the routing request\r
+     * @param evt Tuple that contains: Node that manages the identifier, Identifier that the routing\r
+     * has done on\r
+     */\r
+    void handle(SymphonyProtocol src, Tuple<Node, Double> evt);\r
+}\r
diff --git a/contrib/psg/src/example/symphony/LeaveTest.java b/contrib/psg/src/example/symphony/LeaveTest.java
new file mode 100644 (file)
index 0000000..b4c9167
--- /dev/null
@@ -0,0 +1,77 @@
+package example.symphony;\r
+\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class LeaveTest implements Control {\r
+\r
+    private static final String PAR_NETMANAGER = "symphonynetworkmanager";\r
+    private static final String PAR_NUMBER_LEAVES = "n";\r
+    private static final String PAR_MIN_SIZE = "minsizeOnline";\r
+    private static final String PAR_WAIT_TARGET_SIZE = "waitTargetSizeToStart";\r
+    private final int networkManagerID;\r
+    private final double n;\r
+    private final int minSizeNetwork;\r
+    private int targetSize;\r
+\r
+    public LeaveTest(String prefix) {\r
+        networkManagerID = Configuration.getPid(prefix + "." + PAR_NETMANAGER);\r
+        double nAppo = Configuration.getDouble(prefix + "." + PAR_NUMBER_LEAVES);\r
+        if (!(nAppo > 0.0 && nAppo < 1.0)) {\r
+            n = (int) Math.round(nAppo);\r
+        } else {\r
+            n = nAppo;\r
+        }\r
+\r
+        minSizeNetwork = Configuration.getInt(prefix + "." + PAR_MIN_SIZE, -1);\r
+        targetSize = Configuration.getInt(prefix + "." + PAR_WAIT_TARGET_SIZE, -1);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        if (minSizeNetwork > 0) {\r
+\r
+            int onlineNode = 0;\r
+            AdapterIterableNetwork it = new AdapterIterableNetwork();\r
+            for (Node node : it) {\r
+                if (node.isUp()) {\r
+                    onlineNode++;\r
+                }\r
+            }\r
+\r
+            if (targetSize <= 0 || targetSize <= onlineNode) {\r
+                targetSize = -1;\r
+\r
+                // verify if i have to remove an exact number of nodes or a percentage of them\r
+                int actualN = (int) (n < 1.0 ? Math.ceil(Network.size() * n) : n);\r
+\r
+                for (int i = 0; i < actualN && Network.size() > 0; i++) {\r
+                    if (onlineNode > minSizeNetwork) {\r
+                        Node leaveNode = Network.get(Math.abs(CommonState.r.nextInt()) % Network.size());\r
+\r
+                        while (!leaveNode.isUp()) {\r
+                            leaveNode = Network.get(Math.abs(CommonState.r.nextInt()) % Network.size());\r
+                        }\r
+\r
+                        SymphonyNetworkManager networkManager = (SymphonyNetworkManager) leaveNode.getProtocol(networkManagerID);\r
+\r
+                        networkManager.leave(leaveNode);\r
+\r
+                        onlineNode--;\r
+                    } else {\r
+                        break;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        return false;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/Message.java b/contrib/psg/src/example/symphony/Message.java
new file mode 100644 (file)
index 0000000..5f63d11
--- /dev/null
@@ -0,0 +1,90 @@
+package example.symphony;\r
+\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class Message implements Cloneable {\r
+\r
+    public enum MessageType {\r
+\r
+        ROUTE, ROUTE_RESPONSE, ROUTE_FAIL,\r
+        JOIN, JOIN_RESPONSE,\r
+        UPDATE_NEIGHBOURS, UPDATE_NEIGHBOURS_RESPONSE,\r
+        REQUEST_LONG_RANGE_LINK, ACCEPTED_LONG_RANGE_LINK, REJECT_LONG_RANGE_LINK, DISCONNECT_LONG_RANGE_LINK, UNAVAILABLE_LONG_RANGE_LINK,\r
+        UPDATE_STATUS, UPDATE_STATUS_RESPONSE,\r
+        LEAVE,\r
+        KEEP_ALIVE, KEEP_ALIVE_RESPONSE\r
+    }\r
+    private long hopCounter;\r
+    private MessageType type;\r
+    private Node src;\r
+    private Node currentHop;\r
+    private Object body;\r
+    private static long globalID = 0;\r
+    private final long id;\r
+\r
+    public Message(Object body, Node src, MessageType type) {\r
+        this.type = type;\r
+        this.src = src;\r
+        this.body = body;\r
+        hopCounter = 0;\r
+        id = globalID++;\r
+        currentHop = src;\r
+    }\r
+\r
+    public long getID() {\r
+        return id;\r
+    }\r
+\r
+    public Object getBody() {\r
+        return body;\r
+    }\r
+\r
+    public void incrementHop() {\r
+        hopCounter++;\r
+    }\r
+\r
+    public long getHop() {\r
+        return hopCounter;\r
+    }\r
+\r
+    public MessageType getType() {\r
+        return type;\r
+    }\r
+\r
+    public Node getSourceNode() {\r
+        return src;\r
+    }\r
+\r
+    public Node getCurrentHop() {\r
+        return currentHop;\r
+    }\r
+\r
+    public void setCurrentHop(Node currentHop) {\r
+        this.currentHop = currentHop;\r
+    }\r
+\r
+    @Override\r
+    public Object clone() throws CloneNotSupportedException {\r
+        return super.clone();\r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+\r
+        StringBuilder builder = new StringBuilder();\r
+        builder.append("Message@").append(this.hashCode()).append("[\n");\r
+\r
+        builder.append("\tID : ").append(id).append(",\n");\r
+        builder.append("\tSource ID: ").append(src.getID()).append(",\n");\r
+        builder.append("\tType : ").append(type).append(",\n");\r
+        builder.append("\tBody : ").append(body).append(",\n");\r
+        builder.append("\tCurrent Hop ID: ").append(currentHop.getID()).append(",\n");\r
+        builder.append("\tHop Counter : ").append(hopCounter).append("\n]\n");\r
+\r
+        return builder.toString();\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/NetworkSizeEstimatorProtocolInterface.java b/contrib/psg/src/example/symphony/NetworkSizeEstimatorProtocolInterface.java
new file mode 100644 (file)
index 0000000..ffb8ba9
--- /dev/null
@@ -0,0 +1,13 @@
+package example.symphony;\r
+\r
+import peersim.core.Node;\r
+import peersim.core.Protocol;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public interface NetworkSizeEstimatorProtocolInterface extends Protocol {\r
+\r
+    public int getNetworkSize(Node node);\r
+}\r
diff --git a/contrib/psg/src/example/symphony/RandomRouteTest.java b/contrib/psg/src/example/symphony/RandomRouteTest.java
new file mode 100644 (file)
index 0000000..fe55f33
--- /dev/null
@@ -0,0 +1,48 @@
+package example.symphony;\r
+\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class RandomRouteTest implements Control, Handler {\r
+\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private final int symphonyID;\r
+\r
+    public RandomRouteTest(String prefix) {\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        Node src = Network.get(Math.abs(CommonState.r.nextInt()) % Network.size());\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) src.getProtocol(symphonyID);\r
+        try {\r
+            symphony.route(src, CommonState.r.nextDouble(), this);\r
+        } catch (RoutingException ex) {\r
+            Logger.getLogger(RandomRouteTest.class.getName()).log(Level.SEVERE, ex.getMessage());\r
+        }\r
+\r
+        return false;\r
+\r
+    }\r
+\r
+    public void handle(SymphonyProtocol symphony, Tuple<Node, Double> tuple) {\r
+\r
+        if (tuple == null) {\r
+            Logger.getLogger(RandomRouteTest.class.getName()).log(Level.SEVERE, "FAIL ROUTE RANDOMTEST");\r
+            return;\r
+        }\r
+\r
+        Logger.getLogger(RandomRouteTest.class.getName()).log(Level.FINE, symphony.getIdentifier() + " source find the manager of " + tuple.y + " and it is " + ((SymphonyProtocol) tuple.x.getProtocol(symphonyID)).getIdentifier());\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/RingRouteTest.java b/contrib/psg/src/example/symphony/RingRouteTest.java
new file mode 100644 (file)
index 0000000..06262cb
--- /dev/null
@@ -0,0 +1,150 @@
+package example.symphony;\r
+\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashSet;\r
+import java.util.LinkedList;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import example.symphony.SymphonyProtocol.BootstrapStatus;\r
+import peersim.config.Configuration;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class RingRouteTest implements Control, Handler {\r
+\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private static final String PAR_STARTNODE = "startnode";\r
+    private final int symphonyID;\r
+    private final int indexStartNode;\r
+    private Node start;\r
+    private boolean finished;\r
+    private boolean flagTimeout;\r
+    private HashSet<Node> antiLoopSet;\r
+\r
+    public RingRouteTest(String prefix) {\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+        indexStartNode = Configuration.getInt(prefix + "." + PAR_STARTNODE, 0);\r
+\r
+        finished = true;\r
+        flagTimeout = false;\r
+        antiLoopSet = new HashSet<Node>();\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        if (!finished && flagTimeout) {\r
+\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.WARNING, "Sent msg but no aswer. Timeout. Ring Route Test terminated for Timeout.");\r
+\r
+            finished = true;\r
+            flagTimeout = false;\r
+        }\r
+\r
+        if (finished) {\r
+\r
+            flagTimeout = true;\r
+            antiLoopSet.clear();\r
+\r
+            int indexRealStartNode = indexStartNode;\r
+            Node realStartNode = Network.get(indexStartNode);\r
+            SymphonyProtocol symphony = (SymphonyProtocol) realStartNode.getProtocol(symphonyID);\r
+\r
+            while (!symphony.isBootstrapped() || !realStartNode.isUp()) {\r
+                indexRealStartNode = (indexRealStartNode + 1) % Network.size();\r
+                realStartNode = Network.get(indexRealStartNode);\r
+                symphony = (SymphonyProtocol) realStartNode.getProtocol(symphonyID);\r
+\r
+                if (indexRealStartNode == indexStartNode) {\r
+                    Logger.getLogger(RingRouteTest.class.getName()).log(Level.WARNING, "No ONLINE nodes. The ring is vanished. Ring Route Terminated.");\r
+                    finished = true;\r
+                    flagTimeout = false;\r
+                    return false;\r
+                }\r
+            }\r
+\r
+            start = realStartNode;\r
+            finished = false;\r
+\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.INFO, "RingRoute started.");\r
+\r
+            doRoute(start, true);\r
+        }\r
+\r
+        return false;\r
+    }\r
+\r
+    public void handle(SymphonyProtocol symphony, Tuple<Node, Double> tuple) {\r
+\r
+        if (tuple == null) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.SEVERE, "FAIL RING ROUTING");\r
+            finished = true;\r
+            return;\r
+        }\r
+\r
+        Logger.getLogger(RingRouteTest.class.getName()).log(Level.FINER, symphony.getIdentifier() + " source find the manager of " + tuple.y + " and it is " + ((SymphonyProtocol) tuple.x.getProtocol(symphonyID)).getIdentifier());\r
+\r
+        doRoute(tuple.x, false);\r
+    }\r
+\r
+    private void doRoute(Node node, boolean firstTime) {\r
+\r
+        SymphonyProtocol symphonyStartNode = (SymphonyProtocol) start.getProtocol(symphonyID);\r
+\r
+        if (!symphonyStartNode.isBootstrapped()) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.INFO, "The node i started from left. Ring Route Terminated.");\r
+            finished = true;\r
+            return;\r
+        }\r
+\r
+        if (!firstTime && node.equals(start)) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.INFO, "RingRoute Terminated");\r
+            finished = true;\r
+            return;\r
+        }\r
+\r
+        if (antiLoopSet.contains(node)) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.INFO, "Not able to reach the node that i started from. Ring Route Terminated.");\r
+            finished = true;\r
+            return;\r
+        } else {\r
+            antiLoopSet.add(node);\r
+        }\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        AdapterSymphonyNodeComparator adapterSymphonyNodeComparator = new AdapterSymphonyNodeComparator(new SymphonyNodeComparator(symphonyID, node));\r
+\r
+        Collection<Tuple<Node, BootstrapStatus>> collection = (Collection<Tuple<Node, BootstrapStatus>>) symphony.leftShortRangeLinks.clone();\r
+        LinkedList<Tuple<Node, BootstrapStatus>> list = new LinkedList<Tuple<Node, BootstrapStatus>>(collection);\r
+        Collections.sort(list, adapterSymphonyNodeComparator);\r
+\r
+        Node targetNode = null;\r
+        for (Tuple<Node, BootstrapStatus> tuple : list) {\r
+            if (tuple.y == BootstrapStatus.ONLINE) {\r
+                targetNode = tuple.x;\r
+                break;\r
+            }\r
+        }\r
+\r
+        if (targetNode == null || !targetNode.isUp()) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.WARNING, "Terminated Ring Route but not done completely");\r
+            finished = true;\r
+            return;\r
+        }\r
+\r
+        SymphonyProtocol symphonyTarget = (SymphonyProtocol) targetNode.getProtocol(symphonyID);\r
+        try {\r
+            symphony.route(node, symphonyTarget.getIdentifier(), this);\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.FINEST, "Ring from: " + symphony.getIdentifier() + " to " + symphonyTarget.getIdentifier());\r
+        } catch (RoutingException ex) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.WARNING, "Finito AnelloRoute MA NON FATTO TUTTO");\r
+            finished = true;\r
+        }\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/RoutingException.java b/contrib/psg/src/example/symphony/RoutingException.java
new file mode 100644 (file)
index 0000000..1b6bb9b
--- /dev/null
@@ -0,0 +1,15 @@
+package example.symphony;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class RoutingException extends Exception {\r
+\r
+    public RoutingException() {\r
+    }\r
+\r
+    public RoutingException(String msg) {\r
+        super(msg);\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SimpleNetworkSizeEstimatorProtocol.java b/contrib/psg/src/example/symphony/SimpleNetworkSizeEstimatorProtocol.java
new file mode 100644 (file)
index 0000000..6d17371
--- /dev/null
@@ -0,0 +1,23 @@
+package example.symphony;\r
+\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SimpleNetworkSizeEstimatorProtocol implements NetworkSizeEstimatorProtocolInterface {\r
+\r
+    public SimpleNetworkSizeEstimatorProtocol(String prefix) {\r
+    }\r
+\r
+    public int getNetworkSize(Node node) {\r
+        return Network.size();\r
+    }\r
+\r
+    @Override\r
+    public Object clone() {\r
+        return this;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyEstimationProtocol.java b/contrib/psg/src/example/symphony/SymphonyEstimationProtocol.java
new file mode 100644 (file)
index 0000000..642677d
--- /dev/null
@@ -0,0 +1,106 @@
+package example.symphony;\r
+\r
+import java.util.*;\r
+import peersim.config.Configuration;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyEstimationProtocol implements NetworkSizeEstimatorProtocolInterface {\r
+\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private static final String PAR_S = "s";\r
+    private final int symphonyID;\r
+    private final int s;\r
+\r
+    public SymphonyEstimationProtocol(String prefix) {\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+        s = Configuration.getInt(prefix + "." + PAR_S, -1);\r
+    }\r
+\r
+    /**\r
+     * Implementation of the estimated network size as a variant of the paper one. It use anyway the\r
+     * idea to calculate the size from the length segments but without exchanging the information\r
+     * with the neighbours instead using only the local information.\r
+     */\r
+    public int getNetworkSize(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+        // If the node is not yet inside the ring i return the minimum size (2 nodes)\r
+        if (!symphony.isBootstrapped()) {\r
+            return 2;\r
+        }\r
+\r
+        /*\r
+         * I clone the short range links views (wrapped into an ArrayList because the returned list\r
+         * 'Arrays.asList doesn't support the "removeAll" method or better its size is fixed)\r
+         */\r
+        ArrayList<Tuple<Node, SymphonyProtocol.BootstrapStatus>> leftList = new ArrayList<Tuple<Node, SymphonyProtocol.BootstrapStatus>>(Arrays.asList((Tuple<Node, SymphonyProtocol.BootstrapStatus>[]) symphony.leftShortRangeLinks.toArray(new Tuple[0])));\r
+        ArrayList<Tuple<Node, SymphonyProtocol.BootstrapStatus>> rightList = new ArrayList<Tuple<Node, SymphonyProtocol.BootstrapStatus>>(Arrays.asList((Tuple<Node, SymphonyProtocol.BootstrapStatus>[]) symphony.rightShortRangeLinks.toArray(new Tuple[0])));\r
+\r
+        // Remove the neighbours that are offline\r
+        LinkedList<Tuple<Node, SymphonyProtocol.BootstrapStatus>> offlineNeighbors = new LinkedList<Tuple<Node, SymphonyProtocol.BootstrapStatus>>();\r
+        for (Tuple<Node, SymphonyProtocol.BootstrapStatus> tuple : leftList) {\r
+            if (tuple.y == SymphonyProtocol.BootstrapStatus.OFFLINE) {\r
+                offlineNeighbors.add(tuple);\r
+            }\r
+        }\r
+        leftList.removeAll(offlineNeighbors);\r
+        offlineNeighbors.clear();\r
+        for (Tuple<Node, SymphonyProtocol.BootstrapStatus> tuple : rightList) {\r
+            if (tuple.y == SymphonyProtocol.BootstrapStatus.OFFLINE) {\r
+                offlineNeighbors.add(tuple);\r
+            }\r
+        }\r
+        rightList.removeAll(offlineNeighbors);\r
+\r
+        // Sort the neighbours based on the distance from me\r
+        Comparator<Tuple<Node, SymphonyProtocol.BootstrapStatus>> comparator = new AdapterSymphonyNodeComparator(new SymphonyNodeComparator(symphonyID, symphony.getIdentifier()));\r
+        Collections.sort(leftList, comparator);\r
+        Collections.sort(rightList, comparator);\r
+\r
+        // Calculate the variables to estimated the network size\r
+        double Xs = 0;\r
+        int countS = 0;\r
+\r
+        List<Tuple<Node, SymphonyProtocol.BootstrapStatus>> appoList[] = new List[2];\r
+        appoList[0] = leftList;\r
+        appoList[1] = rightList;\r
+\r
+        double[] appoPrecIdentifier = new double[]{symphony.getIdentifier(), symphony.getIdentifier()};\r
+        int[] appoCurrentIndex = new int[]{0, 0};\r
+\r
+        int realS = (int) (s <= 0 ? Math.log(Network.size() / Math.log(2)) : s);\r
+\r
+        for (int i = 0; i < realS; i++) {\r
+            double precIdentifier = appoPrecIdentifier[i % 2];\r
+            int currentIndex = appoCurrentIndex[i % 2];\r
+            List<Tuple<Node, SymphonyProtocol.BootstrapStatus>> currentList = appoList[i % 2];\r
+\r
+            try {\r
+                double currentIdentifier = ((SymphonyProtocol) currentList.get(currentIndex).x.getProtocol(symphonyID)).getIdentifier();\r
+\r
+                appoPrecIdentifier[i % 2] = currentIdentifier;\r
+                appoCurrentIndex[i % 2] = appoCurrentIndex[i % 2] + 1;\r
+\r
+                double distance = Math.abs(currentIdentifier - precIdentifier);\r
+                Xs += Math.min(distance, 1.0 - distance);\r
+                countS++;\r
+            } catch (IndexOutOfBoundsException ex) {\r
+                // Simply i skip the counting\r
+            }\r
+        }\r
+\r
+        int ret = Xs == 0 ? 0 : (int) Math.round(countS / Xs);\r
+\r
+        return ret;\r
+    }\r
+\r
+    @Override\r
+    public Object clone() {\r
+        return this;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyNetworkBuilder.java b/contrib/psg/src/example/symphony/SymphonyNetworkBuilder.java
new file mode 100644 (file)
index 0000000..a012d60
--- /dev/null
@@ -0,0 +1,157 @@
+package example.symphony;\r
+\r
+import java.util.Collection;\r
+import java.util.Comparator;\r
+import java.util.LinkedList;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import example.symphony.SymphonyProtocol.BootstrapStatus;\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ * Inizializer that create the initial ring\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyNetworkBuilder implements Control {\r
+\r
+    private static final String PAR_SYMHONY = "symphony";\r
+    private static final String PAR_LONG_LINK = "createLongLinks";\r
+    private static final String PAR_MAX_ATTEMPTS = "attempts";\r
+    private final int symphonyID;\r
+    private final boolean createLongRangeLinks;\r
+    private final int MAX_ATTEMPTS;\r
+\r
+    public SymphonyNetworkBuilder(String prefix) {\r
+\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMHONY);\r
+        createLongRangeLinks = Configuration.getBoolean(prefix + "." + PAR_LONG_LINK, true);\r
+        MAX_ATTEMPTS = Configuration.getInt(prefix + "." + PAR_MAX_ATTEMPTS, 5);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        // Sort the network for convenience (from 0.0 to 1.0)\r
+        Network.sort(new Comparator<Node>() {\r
+\r
+            public int compare(Node o1, Node o2) {\r
+\r
+                SymphonyProtocol symphony1 = (SymphonyProtocol) o1.getProtocol(symphonyID);\r
+                SymphonyProtocol symphony2 = (SymphonyProtocol) o2.getProtocol(symphonyID);\r
+\r
+                Double identifier1 = symphony1.getIdentifier();\r
+                Double identifier2 = symphony2.getIdentifier();\r
+\r
+                return identifier1.compareTo(identifier2);\r
+            }\r
+        });\r
+\r
+        int numShortLinksPerSide = ((SymphonyProtocol) Network.get(0).getProtocol(symphonyID)).numberShortRangeLinksPerSide;\r
+\r
+        for (int i = 0; i < Network.size(); i++) {\r
+\r
+            Node node = Network.get(i);\r
+            SymphonyProtocol symphonyNode = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+            // Create the short links\r
+            for (int j = 1; j <= numShortLinksPerSide; j++) {\r
+\r
+                int pos = i - j;\r
+                pos = pos < 0 ? Network.size() + pos : pos;\r
+                symphonyNode.rightShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(Network.get(pos), BootstrapStatus.ONLINE));\r
+\r
+                pos = (i + j) % Network.size();\r
+                symphonyNode.leftShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(Network.get(pos), BootstrapStatus.ONLINE));\r
+            }\r
+\r
+            symphonyNode.loggedIntoNetwork = SymphonyProtocol.BootstrapStatus.ONLINE;\r
+        }\r
+\r
+        /*\r
+         * UPDATE: Putted a flag to decide if perform this part of code or not at configuration\r
+         * time. At default i create the long range links.\r
+         *\r
+         * The Long Range Links could be left to the networkmanager but the tests that we'll do have\r
+         * to put into account that in an initial phase will be some message exchanging to create\r
+         * the long range links and so the latency is faked... for that reason the long range links\r
+         * are created manually here such a way to have a complete symphony network from the\r
+         * beginning.\r
+         */\r
+        if (createLongRangeLinks) {\r
+            for (Node node : new AdapterIterableNetwork()) {\r
+\r
+                SymphonyProtocol symphonyNode = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+                // Create the long links\r
+                int k = (int) Math.ceil(Math.log(Network.size()) / Math.log(2));\r
+\r
+                if (symphonyNode.fixedLongRangeLinks) {\r
+                    k = symphonyNode.numberFixedLongRangeLinks;\r
+                }\r
+\r
+                Collection<Node> allShortLinks = new LinkedList<Node>();\r
+                for (Tuple<Node, BootstrapStatus> shortTuple : symphonyNode.leftShortRangeLinks) {\r
+                    allShortLinks.add(shortTuple.x);\r
+                }\r
+                for (Tuple<Node, BootstrapStatus> shortTuple : symphonyNode.rightShortRangeLinks) {\r
+                    allShortLinks.add(shortTuple.x);\r
+                }\r
+\r
+                int j = 0;\r
+                int attempts = MAX_ATTEMPTS;\r
+                while (j <= k) {\r
+\r
+                    double distance = Math.exp(k * (CommonState.r.nextDouble() - 1.0));\r
+                    double targetIdentifier = (symphonyNode.getIdentifier() + distance) % 1;\r
+\r
+                    Node targetNode;\r
+                    try {\r
+\r
+                        // use the unidirectional routing because i want to catch the manager\r
+                        targetNode = symphonyNode.findClosestNode(targetIdentifier, new AdapterIterableNetwork(), true);\r
+                        SymphonyProtocol symphonyTargetNode = (SymphonyProtocol) targetNode.getProtocol(symphonyID);\r
+                        if (!targetNode.equals(node)\r
+                                && !symphonyNode.longRangeLinksOutgoing.contains(targetNode)\r
+                                && symphonyTargetNode.longRangeLinksIncoming.size() < (2 * k)\r
+                                && !allShortLinks.contains(targetNode)) {\r
+\r
+                            boolean fresh = symphonyTargetNode.longRangeLinksIncoming.add(node);\r
+\r
+                            if (fresh) {\r
+                                j++;\r
+                                attempts = MAX_ATTEMPTS;\r
+                                symphonyNode.longRangeLinksOutgoing.add(targetNode);\r
+                            } else {\r
+                                attempts--;\r
+                                if (attempts <= 0) { // Because i don't want to loop i try a finite number of times\r
+                                    attempts = MAX_ATTEMPTS;\r
+                                    j++;\r
+                                }\r
+\r
+                            }\r
+                        } else {\r
+                            attempts--;\r
+                            if (attempts <= 0) { // Because i don't want to loop i try a finite number of times\r
+                                attempts = MAX_ATTEMPTS;\r
+                                j++;\r
+                            }\r
+\r
+                        }\r
+                    } catch (RoutingException ex) {\r
+                        Logger.getLogger(SymphonyNetworkBuilder.class.getName()).log(Level.SEVERE, null, ex);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        // Shuffle\r
+        Network.shuffle();\r
+\r
+        return false;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyNetworkChecker.java b/contrib/psg/src/example/symphony/SymphonyNetworkChecker.java
new file mode 100644 (file)
index 0000000..d5f2aef
--- /dev/null
@@ -0,0 +1,123 @@
+package example.symphony;\r
+\r
+import java.util.Collections;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import example.symphony.SymphonyProtocol.BootstrapStatus;\r
+import peersim.config.Configuration;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyNetworkChecker implements Control {\r
+\r
+    private static final String PAR_SYMHONY = "symphony";\r
+    private static final String PAR_NETSIZE = "networkestimator";\r
+    private final int symphonyID;\r
+    private final int networkEstimatorID;\r
+\r
+    public SymphonyNetworkChecker(String prefix) {\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMHONY);\r
+        networkEstimatorID = Configuration.getPid(prefix + "." + PAR_NETSIZE);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        boolean isNotOK = false;\r
+\r
+        Set<Double> idSet = new HashSet<Double>();\r
+        Iterable<Node> coll = new AdapterIterableNetwork();\r
+\r
+        int countOnline = 0;\r
+        int count = 0;\r
+        int notBootstrapped = 0;\r
+        int countKO = 0;\r
+        int disconnected = 0;\r
+\r
+        for (Node node : coll) {\r
+            SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+            if (!node.isUp()) {\r
+                disconnected++;\r
+            } else {\r
+                count++;\r
+            }\r
+\r
+            if (symphony.loggedIntoNetwork == SymphonyProtocol.BootstrapStatus.ONLINE) {\r
+\r
+                countOnline++;\r
+\r
+                NetworkSizeEstimatorProtocolInterface networkEstimator = (NetworkSizeEstimatorProtocolInterface) node.getProtocol(networkEstimatorID);\r
+                int k = (int) Math.ceil(Math.log(networkEstimator.getNetworkSize(node)) / Math.log(2));\r
+\r
+                boolean checkLeftShortRangeLinks = symphony.leftShortRangeLinks.size() > 0 && symphony.leftShortRangeLinks.size() <= symphony.numberShortRangeLinksPerSide;\r
+                boolean checkRightShortRangeLinks = symphony.rightShortRangeLinks.size() > 0 && symphony.rightShortRangeLinks.size() <= symphony.numberShortRangeLinksPerSide;\r
+\r
+                boolean oneNeighborOnline = false;\r
+                for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+                    if (leftTuple.y != BootstrapStatus.ONLINE && leftTuple.y != BootstrapStatus.OFFLINE) {\r
+                        notBootstrapped++;\r
+                    } else {\r
+                        oneNeighborOnline = true;\r
+                        checkLeftShortRangeLinks = checkLeftShortRangeLinks && SymphonyProtocol.isLeftNeighbour(node, leftTuple.x);\r
+                    }\r
+                }\r
+                checkLeftShortRangeLinks = checkLeftShortRangeLinks && oneNeighborOnline;\r
+\r
+                oneNeighborOnline = false;\r
+                for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+                    if (rightTuple.y != BootstrapStatus.ONLINE && rightTuple.y != BootstrapStatus.OFFLINE) {\r
+                        notBootstrapped++;\r
+                    } else {\r
+                        oneNeighborOnline = true;\r
+                        checkRightShortRangeLinks = checkRightShortRangeLinks && !SymphonyProtocol.isLeftNeighbour(node, rightTuple.x);\r
+                    }\r
+                }\r
+                checkRightShortRangeLinks = checkRightShortRangeLinks && oneNeighborOnline;\r
+\r
+                // Check if the node is in its neighbours\r
+                if (checkLeftShortRangeLinks) {\r
+                    AdapterSymphonyNodeComparator comparator = new AdapterSymphonyNodeComparator(new SymphonyNodeComparator(symphonyID, node));\r
+                    checkLeftShortRangeLinks = checkLeftShortRangeLinks && !Collections.min(symphony.leftShortRangeLinks, comparator).x.equals(node);\r
+                }\r
+\r
+                if (checkRightShortRangeLinks) {\r
+                    AdapterSymphonyNodeComparator comparator = new AdapterSymphonyNodeComparator(new SymphonyNodeComparator(symphonyID, node));\r
+                    checkRightShortRangeLinks = checkRightShortRangeLinks && !Collections.min(symphony.rightShortRangeLinks, comparator).x.equals(node);\r
+                }\r
+\r
+                boolean checkLongRangeLinksOutgoing = !symphony.longRangeLinksOutgoing.contains(node);\r
+                boolean checkLongRangeLinksIncoming = /*\r
+                         * symphony.longRangeLinksIncoming.size() <= (2 * k) &&\r
+                         */ !symphony.longRangeLinksIncoming.contains(node);\r
+\r
+                boolean checkUniqueID = !idSet.contains(symphony.getIdentifier());\r
+                idSet.add(symphony.getIdentifier());\r
+\r
+                boolean nextIsNotOK = !(checkUniqueID && checkLeftShortRangeLinks && checkRightShortRangeLinks && checkLongRangeLinksOutgoing && checkLongRangeLinksIncoming);\r
+\r
+                if (nextIsNotOK) {\r
+                    countKO++;\r
+                    Logger.getLogger(SymphonyNetworkChecker.class.getName()).log(Level.SEVERE, "OPS");\r
+                }\r
+\r
+                isNotOK = isNotOK || nextIsNotOK;\r
+            }\r
+        }\r
+\r
+        System.out.println("Error: " + countKO);\r
+        System.out.println("Online: " + countOnline + "/" + count);\r
+        System.out.println("Not Bootstrapped: " + notBootstrapped);\r
+        System.out.println("Disconnected: " + disconnected);\r
+        System.out.println("Network Size: " + Network.size());\r
+\r
+        return isNotOK;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyNetworkManager.java b/contrib/psg/src/example/symphony/SymphonyNetworkManager.java
new file mode 100644 (file)
index 0000000..4a1277f
--- /dev/null
@@ -0,0 +1,864 @@
+package example.symphony;\r
+\r
+import java.util.*;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import example.symphony.Message.MessageType;\r
+import example.symphony.SymphonyProtocol.BootstrapStatus;\r
+import peersim.cdsim.CDProtocol;\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Fallible;\r
+import peersim.core.Node;\r
+import peersim.edsim.EDProtocol;\r
+import peersim.transport.Transport;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyNetworkManager implements EDProtocol, CDProtocol {\r
+\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private static final String PAR_TRANSP = "transport";\r
+    private static final String PAR_ATTEMPTS = "attempts";\r
+    private static final String PAR_NETSIZE = "networkestimator";\r
+    private static final String PAR_NUM_TIMEOUT = "nTimeout";\r
+    private static final String PAR_RELINKING = "relinking";\r
+    private static final String PAR_RELINKING_LOWER_BOUND = "relinkingLowerBound";\r
+    private static final String PAR_RELINKING_UPPER_BOUND = "relinkingUpperBound";\r
+    private static final int DEFAULT_K = 1;\r
+    private static final int DEFAULT_N = 2;\r
+    private static final double DEFAULT_RELINKING_LOWER_BOUND = 0.5;\r
+    private static final double DEFAULT_RELINKING_UPPER_BOUND = 2.0;\r
+    private final String prefix;\r
+    private final int symphonyID;\r
+    private final int transportID;\r
+    private final int networkEstimatorID;\r
+    private final int attempts;\r
+    private final int pid;\r
+    private final int nTimeout;\r
+    private final HashMap<Node, Integer> keepAliveMap;\r
+    private final boolean relinkingProtocolActivated;\r
+    private final double relinkingUpperBound;\r
+    private final double relinkingLowerBound;\r
+    private int k = DEFAULT_K; // Number of Long Range Link\r
+    private int n = DEFAULT_N; // Estimation Network size\r
+    private static boolean firstPrintConfig = true;\r
+    /*\r
+     * Estimation Network size at which last long distance link was established, at the beginning -1\r
+     * to indicate that we never had Long Range Links\r
+     */\r
+    private int nLink = -1;\r
+    private int currentAttempts;\r
+\r
+    public SymphonyNetworkManager(String prefix) {\r
+\r
+        this.prefix = prefix;\r
+        pid = Configuration.lookupPid(prefix.replaceAll("protocol.", ""));\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+        transportID = Configuration.getPid(prefix + "." + PAR_TRANSP);\r
+        networkEstimatorID = Configuration.getPid(prefix + "." + PAR_NETSIZE);\r
+        attempts = Configuration.getInt(prefix + "." + PAR_ATTEMPTS);\r
+        nTimeout = Configuration.getInt(prefix + "." + PAR_NUM_TIMEOUT, 10);\r
+        relinkingProtocolActivated = !Configuration.getString(prefix + "." + PAR_RELINKING, "on").toLowerCase().equals("off");\r
+        double relinkingLowerBoundAppo = Configuration.getDouble(prefix + "." + PAR_RELINKING_LOWER_BOUND, DEFAULT_RELINKING_LOWER_BOUND);\r
+        double relinkingUpperBoundAppo = Configuration.getDouble(prefix + "." + PAR_RELINKING_UPPER_BOUND, DEFAULT_RELINKING_UPPER_BOUND);\r
+        if (relinkingLowerBoundAppo > relinkingUpperBoundAppo) {\r
+            relinkingLowerBound = DEFAULT_RELINKING_LOWER_BOUND;\r
+            relinkingUpperBound = DEFAULT_RELINKING_UPPER_BOUND;\r
+        } else {\r
+            relinkingLowerBound = relinkingLowerBoundAppo;\r
+            relinkingUpperBound = relinkingUpperBoundAppo;\r
+        }\r
+\r
+        keepAliveMap = new HashMap<Node, Integer>();\r
+\r
+        printConfig();\r
+    }\r
+\r
+    private void printConfig() {\r
+\r
+        if (firstPrintConfig) {\r
+            firstPrintConfig = false;\r
+            System.out.println(SymphonyNetworkManager.class.getSimpleName() + " Configuration:");\r
+            System.out.println("- Attempts per LongRangeLinks: " + attempts);\r
+            System.out.println("- Number of Timeout before a node is considered OFFLINE (through Keep-alive):" + nTimeout);\r
+            System.out.println("- Relinking: " + (relinkingProtocolActivated ? "ON" : "OFF"));\r
+            System.out.println("- Relinking Range: [" + relinkingLowerBound + ", " + relinkingUpperBound + "]");\r
+            System.out.println("-------------------------------\n");\r
+        }\r
+    }\r
+\r
+    public void join(final Node node, final Node bootstrapNode) throws RoutingException {\r
+        final SymphonyProtocol bootstrapSymphony = (SymphonyProtocol) bootstrapNode.getProtocol(symphonyID);\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+        /*\r
+         * Search (through the bootstrap node) and contact the Manager Node of myself such a way to\r
+         * be able to insert myself into the ring and create the short links\r
+         *\r
+         */\r
+        bootstrapSymphony.route(bootstrapNode, symphony.getIdentifier(), new Handler() {\r
+\r
+            public void handle(SymphonyProtocol src, Tuple<Node, Double> tuple) {\r
+                if (tuple == null) {\r
+                    Logger.getLogger(SymphonyNetworkManager.class.getName()).log(Level.SEVERE, "FAIL ROUTE JOIN");\r
+                    node.setFailState(Fallible.DEAD);\r
+                    return;\r
+                }\r
+\r
+                Node managerNode = tuple.x;\r
+\r
+                Transport transport = (Transport) node.getProtocol(transportID);\r
+                Message msg = new Message(node, node, MessageType.JOIN);\r
+                transport.send(node, managerNode, msg, pid);\r
+            }\r
+        });\r
+\r
+        // The Long Range Links are added after that i joined the ring (before i can't because i haven't got the nodes to do the routing)\r
+    }\r
+\r
+    /**\r
+     * Conservative Re-Linking (i reuse the ones already created: not all fresh)\r
+     *\r
+     * @param node\r
+     */\r
+    public void updateLongRangeLinks(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+        // if too much links i delete the farest ones\r
+        while (symphony.longRangeLinksOutgoing.size() > k) {\r
+            Node distantNode = Collections.max(symphony.longRangeLinksOutgoing, new SymphonyNodeComparator(symphonyID, node));\r
+            symphony.longRangeLinksOutgoing.remove(distantNode);\r
+\r
+            // Communicate to the outgoing node that it ins't anymore one of my long range links\r
+            Message disconnectMsg = new Message(null, node, MessageType.DISCONNECT_LONG_RANGE_LINK);\r
+            transport.send(node, distantNode, disconnectMsg, pid);\r
+        }\r
+\r
+        // I can search Long Range Links only if i'm into the ring and i'm able to do routing\r
+        if (symphony.isBootstrapped()) {\r
+            // if only few i try again, untill attempts times, to add new ones\r
+            int difference = k - symphony.longRangeLinksOutgoing.size();\r
+            currentAttempts = attempts;\r
+            for (int i = 0; i < difference; i++) {\r
+                sendLongRangeLinkRequest(symphony, node);\r
+            }\r
+        }\r
+    }\r
+    private static final int MAX_ANTILOOP_COUNT_MANAGER_MYSELF = 5;\r
+    private int antiLoopManagerMySelf = 0;\r
+\r
+    private void sendLongRangeLinkRequest(final SymphonyProtocol symphony, final Node node) {\r
+        boolean routingOk;\r
+        do {\r
+            double distance = Math.exp((Math.log(n) / Math.log(2)) * (CommonState.r.nextDouble() - 1.0)); // Harmonic Distribution\r
+            double targetIdentifier = (symphony.getIdentifier() + distance) % 1;\r
+            try {\r
+\r
+                symphony.route(node, targetIdentifier, new Handler() {\r
+\r
+                    public void handle(SymphonyProtocol src, Tuple<Node, Double> tuple) {\r
+\r
+                        if (tuple == null) {\r
+                            Logger.getLogger(SymphonyNetworkManager.class.getName()).log(Level.SEVERE, "FAIL ROUTE SENDLONGRANGELINKREQUEST");\r
+                            return;\r
+                        }\r
+\r
+                        Collection<Node> allShortLinks = new LinkedList<Node>();\r
+                        for (Tuple<Node, BootstrapStatus> shortTuple : symphony.leftShortRangeLinks) {\r
+                            allShortLinks.add(shortTuple.x);\r
+                        }\r
+                        for (Tuple<Node, BootstrapStatus> shortTuple : symphony.rightShortRangeLinks) {\r
+                            allShortLinks.add(shortTuple.x);\r
+                        }\r
+\r
+                        /*\r
+                         *\r
+                         * I'm myself one of my short links, special case... i try again without\r
+                         * reduce the attempts for a maximum of MAX_ANTILOOP_COUNT_MANAGER_MYSELF\r
+                         * times after that i start again to reduce the attempts\r
+                         */\r
+                        if (tuple.x.equals(node) || allShortLinks.contains(tuple.x)) {\r
+\r
+                            if (antiLoopManagerMySelf < MAX_ANTILOOP_COUNT_MANAGER_MYSELF) {\r
+\r
+                                antiLoopManagerMySelf++;\r
+                                sendLongRangeLinkRequest(symphony, node);\r
+                            } else {\r
+                                antiLoopManagerMySelf = 0;\r
+                                currentAttempts--;\r
+                            }\r
+                        } else {\r
+\r
+                            boolean alreadyAdded = symphony.longRangeLinksOutgoing.contains(tuple.x);\r
+                            /*\r
+                             *\r
+                             * OPINABLE: DESCREASE ATTEMPTS ONLY FOR REJECT? If yes i have to manage\r
+                             * the possible loop (nodi exhaurited so already all added)\r
+                             */\r
+                            if (alreadyAdded && currentAttempts > 0) {\r
+                                currentAttempts--;\r
+                                sendLongRangeLinkRequest(symphony, node);\r
+                            } else if (!alreadyAdded) {\r
+                                Message msg = new Message(null, node, MessageType.REQUEST_LONG_RANGE_LINK);\r
+                                Transport transport = (Transport) node.getProtocol(transportID);\r
+                                transport.send(node, tuple.x, msg, pid);\r
+                            }\r
+                        }\r
+                    }\r
+                });\r
+                routingOk = true;\r
+            } catch (RoutingException ex) {\r
+                routingOk = false;\r
+            }\r
+        } while (!routingOk);\r
+    }\r
+\r
+    public void leave(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+        if (symphony.loggedIntoNetwork != BootstrapStatus.OFFLINE) {\r
+            Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+            symphony.loggedIntoNetwork = BootstrapStatus.OFFLINE;\r
+\r
+            // Communicate that i'm leaving to the outgoing (that i point to) nodes\r
+            for (Node outgoingNode : symphony.longRangeLinksOutgoing) {\r
+                Message disconnectMsg = new Message(null, node, MessageType.DISCONNECT_LONG_RANGE_LINK);\r
+                transport.send(node, outgoingNode, disconnectMsg, pid);\r
+            }\r
+\r
+            // Communicate that i'm leaving to the incoming (that they point to me) nodes\r
+            for (Node incomingNode : symphony.longRangeLinksIncoming) {\r
+                Message unavailableMsg = new Message(null, node, MessageType.UNAVAILABLE_LONG_RANGE_LINK);\r
+                transport.send(node, incomingNode, unavailableMsg, pid);\r
+            }\r
+\r
+            // Communicate to my neighbours (short range links) that i'm leaving and i send to them the near neighbours\r
+            for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+                Message leaveMsg = new Message(symphony.rightShortRangeLinks.clone(), node, MessageType.LEAVE);\r
+                transport.send(node, leftTuple.x, leaveMsg, pid);\r
+            }\r
+\r
+            for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+                Message leaveMsg = new Message(symphony.leftShortRangeLinks.clone(), node, MessageType.LEAVE);\r
+                transport.send(node, rightTuple.x, leaveMsg, pid);\r
+            }\r
+\r
+            node.setFailState(Fallible.DEAD);\r
+        }\r
+    }\r
+\r
+    public void processEvent(Node node, int pid, Object event) {\r
+\r
+        Message msg = (Message) event;\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+        Collection<Tuple<Node, BootstrapStatus>> collection = null;\r
+        switch (msg.getType()) {\r
+            case JOIN:\r
+                // I send my  current neighbours to the entering node\r
+                collection = (Collection<Tuple<Node, BootstrapStatus>>) symphony.leftShortRangeLinks.clone();\r
+                collection.addAll((Collection<Tuple<Node, BootstrapStatus>>) symphony.rightShortRangeLinks.clone());\r
+                Message responseMsg = new Message(collection, node, MessageType.JOIN_RESPONSE);\r
+                transport.send(node, msg.getSourceNode(), responseMsg, pid);\r
+\r
+                /*\r
+                 * Update my neighbours list, adding the new one (for sure it is entering in the\r
+                 * left side)\r
+                 *\r
+                 * Put to "ONLINE_AND_ALL_NEIGHBOURS_OFFLINE" because maybe the bootstrap phase is\r
+                 * not terminated yet (ashyncronous communication)\r
+                 */\r
+                symphony.leftShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(msg.getSourceNode(), BootstrapStatus.ONLINE_AND_ALL_NEIGHBOURS_OFFLINE));\r
+\r
+\r
+                fixNeighbours(node, symphony.leftShortRangeLinks);\r
+                break;\r
+            case JOIN_RESPONSE:\r
+\r
+                Collection<Tuple<Node, BootstrapStatus>> tupleCollection = (Collection<Tuple<Node, BootstrapStatus>>) msg.getBody();\r
+\r
+                /*\r
+                 *\r
+                 * My manager is a right neighbour. The manager is already inside the ring, boostrap\r
+                 * obliviously ok\r
+                 */\r
+                symphony.rightShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(msg.getSourceNode(), BootstrapStatus.ONLINE));\r
+\r
+                // Set my neighbours in the correct position\r
+                for (Tuple<Node, BootstrapStatus> tuple : tupleCollection) {\r
+                    if (SymphonyProtocol.isLeftNeighbour(node, tuple.x)) {\r
+                        symphony.leftShortRangeLinks.add(tuple);\r
+                    } else {\r
+                        symphony.rightShortRangeLinks.add(tuple);\r
+                    }\r
+                }\r
+\r
+                fixNeighbours(node, symphony.leftShortRangeLinks);\r
+                fixNeighbours(node, symphony.rightShortRangeLinks);\r
+\r
+                // Update bootstrap status\r
+                checkBootstrapStatus(node);\r
+\r
+                // I send the refresh command such a way to exchange the views\r
+                refreshNeighbours(node);\r
+\r
+                // Update Long Range Links, because it's at the beginning is the same as adding k\r
+                updateLongRangeLinks(node);\r
+                break;\r
+            case UPDATE_NEIGHBOURS:\r
+\r
+                Collection<Tuple<Node, BootstrapStatus>> collectionCloned = ((Collection<Tuple<Node, BootstrapStatus>>) symphony.leftShortRangeLinks.clone());\r
+                collectionCloned.addAll(((Collection<Tuple<Node, BootstrapStatus>>) symphony.rightShortRangeLinks.clone()));\r
+\r
+                // Send my neighbours such a way it can also update itself\r
+                Message responseUpdateMsg = new Message(collectionCloned, node, MessageType.UPDATE_NEIGHBOURS_RESPONSE);\r
+                transport.send(node, msg.getSourceNode(), responseUpdateMsg, pid);\r
+\r
+                // Update my view with the new node\r
+                Tuple<Node, BootstrapStatus> neighbourTuple = new Tuple<Node, BootstrapStatus>(msg.getSourceNode(), (BootstrapStatus) msg.getBody());\r
+                if (SymphonyProtocol.isLeftNeighbour(node, msg.getSourceNode())) {\r
+                    collection = symphony.leftShortRangeLinks;\r
+                } else {\r
+                    collection = symphony.rightShortRangeLinks;\r
+                }\r
+                collection.add(neighbourTuple);\r
+\r
+                fixNeighbours(node, collection);\r
+                fixLookAheadMap(node);\r
+                break;\r
+            case UPDATE_NEIGHBOURS_RESPONSE:\r
+\r
+                Collection<Tuple<Node, BootstrapStatus>> responseCollection = (Collection<Tuple<Node, BootstrapStatus>>) msg.getBody();\r
+\r
+                for (Tuple<Node, BootstrapStatus> neighbourResponseTuple : responseCollection) {\r
+                    if (SymphonyProtocol.isLeftNeighbour(node, neighbourResponseTuple.x)) {\r
+                        collection = symphony.leftShortRangeLinks;\r
+                    } else {\r
+                        collection = symphony.rightShortRangeLinks;\r
+                    }\r
+                    collection.add(neighbourResponseTuple);\r
+                }\r
+\r
+                // Fix the neighbours number to the maximum allow and maybe remove myself from the list\r
+                fixNeighbours(node, symphony.leftShortRangeLinks);\r
+                fixNeighbours(node, symphony.rightShortRangeLinks);\r
+                fixLookAheadMap(node);\r
+                break;\r
+            case UPDATE_STATUS:\r
+            case UPDATE_STATUS_RESPONSE:\r
+\r
+                Node updNode = msg.getSourceNode();\r
+                BootstrapStatus updStatus = (BootstrapStatus) msg.getBody();\r
+\r
+                // I search the neighbour and i update its status\r
+                boolean founded = false;\r
+\r
+                // Try to see if it is on the left\r
+                for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+                    if (leftTuple.x.equals(updNode)) {\r
+                        symphony.leftShortRangeLinks.remove(leftTuple);\r
+                        symphony.leftShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(updNode, updStatus));\r
+\r
+                        founded = true;\r
+                        break;\r
+                    }\r
+                }\r
+\r
+                // If it isn't on the left i try with the neighbours on the right\r
+                if (!founded) {\r
+                    for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+                        if (rightTuple.x.equals(updNode)) {\r
+                            symphony.rightShortRangeLinks.remove(rightTuple);\r
+                            symphony.rightShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(updNode, updStatus));\r
+\r
+                            break;\r
+                        }\r
+                    }\r
+\r
+                    fixNeighbours(node, symphony.rightShortRangeLinks);\r
+                } else {\r
+                    fixNeighbours(node, symphony.leftShortRangeLinks);\r
+                }\r
+\r
+                checkBootstrapStatusAndAlert(node);\r
+\r
+                if (msg.getType() == MessageType.UPDATE_STATUS) {\r
+                    Message responseUpdStatus = new Message(symphony.loggedIntoNetwork, node, MessageType.UPDATE_STATUS_RESPONSE);\r
+                    transport.send(node, updNode, responseUpdStatus, pid);\r
+                }\r
+\r
+                break;\r
+            case REQUEST_LONG_RANGE_LINK:\r
+                MessageType responseType = MessageType.REJECT_LONG_RANGE_LINK;\r
+                if (symphony.longRangeLinksIncoming.size() < (2 * k)) {\r
+                    boolean added = symphony.longRangeLinksIncoming.add(msg.getSourceNode());\r
+                    if (added) {\r
+                        responseType = MessageType.ACCEPTED_LONG_RANGE_LINK;\r
+                    }\r
+                }\r
+                Message responseLongLinkMsg = new Message(null, node, responseType);\r
+                transport.send(node, msg.getSourceNode(), responseLongLinkMsg, pid);\r
+                break;\r
+            case ACCEPTED_LONG_RANGE_LINK:\r
+                nLink = n;\r
+                symphony.longRangeLinksOutgoing.add(msg.getSourceNode());\r
+                break;\r
+            case REJECT_LONG_RANGE_LINK:\r
+                if (currentAttempts > 0) {\r
+                    currentAttempts--;\r
+                    sendLongRangeLinkRequest(symphony, node);\r
+                }\r
+                break;\r
+            case DISCONNECT_LONG_RANGE_LINK:\r
+                symphony.longRangeLinksIncoming.remove(msg.getSourceNode());\r
+                symphony.lookAheadMap.put(msg.getSourceNode(), null);\r
+                break;\r
+            case UNAVAILABLE_LONG_RANGE_LINK:\r
+                symphony.longRangeLinksOutgoing.remove(msg.getSourceNode());\r
+                symphony.lookAheadMap.put(msg.getSourceNode(), null);\r
+                break;\r
+            case LEAVE:\r
+                Tuple<Node, BootstrapStatus> foundedTuple = null;\r
+\r
+                // Verify if the node that is leaving is a left neighbour\r
+                for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+                    if (leftTuple.x.equals(msg.getSourceNode())) {\r
+                        collection = symphony.leftShortRangeLinks;\r
+                        foundedTuple = leftTuple;\r
+                        break;\r
+                    }\r
+                }\r
+\r
+                // Verify if the node that is leaving is a right neighbour\r
+                if (collection == null) {\r
+                    for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+                        if (rightTuple.x.equals(msg.getSourceNode())) {\r
+                            collection = symphony.rightShortRangeLinks;\r
+                            foundedTuple = rightTuple;\r
+                            break;\r
+                        }\r
+                    }\r
+                }\r
+\r
+                // if i've found the neighbour i remove it and i add to myself its neighbours\r
+                if (collection != null) {\r
+                    collection.addAll((Collection<Tuple<Node, BootstrapStatus>>) msg.getBody());\r
+                    collection.remove(foundedTuple);\r
+                    fixNeighbours(node, collection);\r
+\r
+                    // Update status and ready to send an alert in case i'm out of the ring\r
+                    checkBootstrapStatusAndAlert(node);\r
+                }\r
+                break;\r
+            case KEEP_ALIVE:\r
+                Set<Double>[] lookAheadSetArray = new LinkedHashSet[2];\r
+\r
+                /*\r
+                 * Check if the contacting node is doing lookAhead and in case of affirmative answer\r
+                 * i provide to it the long range link identifiers (according to my routing mode)\r
+                 */\r
+                if ((Boolean) msg.getBody()) {\r
+                    int i = 0;\r
+                    Iterable[] iterableArray;\r
+                    if (symphony.bidirectionalRouting) {\r
+                        iterableArray = new Iterable[]{symphony.longRangeLinksOutgoing, symphony.longRangeLinksIncoming};\r
+                    } else {\r
+                        iterableArray = new Iterable[]{symphony.longRangeLinksOutgoing};\r
+                    }\r
+\r
+                    for (Iterable<Node> iterable : iterableArray) {\r
+                        lookAheadSetArray[i] = new LinkedHashSet<Double>();\r
+                        Set<Double> lookAheadSet = lookAheadSetArray[i];\r
+                        Iterator<Node> it = iterable.iterator();\r
+                        while (it.hasNext()) {\r
+                            Node longLinkNode = it.next();\r
+                            lookAheadSet.add(((SymphonyProtocol) longLinkNode.getProtocol(symphonyID)).getIdentifier());\r
+                        }\r
+                        i++;\r
+                    }\r
+                }\r
+\r
+                transport.send(node, msg.getSourceNode(), new Message(lookAheadSetArray, node, MessageType.KEEP_ALIVE_RESPONSE), pid);\r
+                break;\r
+            case KEEP_ALIVE_RESPONSE:\r
+                // Reset the counter to 0\r
+                keepAliveMap.put(msg.getSourceNode(), 0);\r
+\r
+                if (symphony.lookAhead) {\r
+                    symphony.lookAheadMap.put(msg.getSourceNode(), (Set<Double>[]) msg.getBody());\r
+                }\r
+\r
+                break;\r
+        }\r
+    }\r
+\r
+    /**\r
+     *\r
+     * Update the status and communicate immediately to the neighbours if the node is gone out from\r
+     * the ring (and before it was inside)\r
+     *\r
+     * @param node\r
+     */\r
+    private void checkBootstrapStatusAndAlert(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        BootstrapStatus beforeStatus = symphony.loggedIntoNetwork;\r
+\r
+        checkBootstrapStatus(node);\r
+\r
+        // Instead of waiting that the update happens periodically i do it now because i'm out of the ring and before i wasn't\r
+        if (symphony.loggedIntoNetwork != beforeStatus && !symphony.isBootstrapped()) {\r
+            updateBootstrapStatusNeighbours(node, true);\r
+        }\r
+    }\r
+\r
+    private void fixNeighbours(Node node, Collection<Tuple<Node, BootstrapStatus>> neighbours) {\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+        // Remove duplicates, remove that ones that are in an obsolete status\r
+        Collection<Tuple<Node, BootstrapStatus>> removedNeighbours = new LinkedHashSet<Tuple<Node, BootstrapStatus>>();\r
+        for (Tuple<Node, BootstrapStatus> tuple : neighbours) {\r
+\r
+            // Remove myself from the neighbours list\r
+            if (tuple.x.equals(node)) {\r
+                removedNeighbours.add(tuple);\r
+                continue;\r
+            }\r
+\r
+            EnumSet<BootstrapStatus> status = EnumSet.allOf(BootstrapStatus.class);\r
+            status.remove(tuple.y);\r
+\r
+            for (BootstrapStatus opposite : status) {\r
+                Tuple<Node, BootstrapStatus> oppositeNeighbour = new Tuple<Node, BootstrapStatus>(tuple.x, opposite);\r
+                if (neighbours.contains(oppositeNeighbour)) {\r
+                    if (tuple.y != BootstrapStatus.ONLINE) {\r
+                        removedNeighbours.add(new Tuple<Node, BootstrapStatus>(tuple.x, BootstrapStatus.OFFLINE));\r
+                        if (opposite == BootstrapStatus.ONLINE) {\r
+                            removedNeighbours.add(new Tuple<Node, BootstrapStatus>(tuple.x, BootstrapStatus.ONLINE_AND_ALL_NEIGHBOURS_OFFLINE));\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        neighbours.removeAll(removedNeighbours);\r
+\r
+        /*\r
+         *\r
+         * I count the neighbours that are in the ONLINE status but before i remove the ones that\r
+         * are gone in timeout during the keep-alive procedure because can be someone that is old\r
+         * but not remove from the exchanging views (UPDATE_NEIGHBOURS) procedure and are not\r
+         * effectively online. To do anyway the possibility to the node to join again i decrease its\r
+         * timeout value. This only if the node is ONLINE and so i'm really interested that it is ok\r
+         * for the routing.\r
+         *\r
+         */\r
+        int onlineNeighbours = 0;\r
+        for (Tuple<Node, BootstrapStatus> tuple : neighbours) {\r
+\r
+            Integer value = keepAliveMap.get(tuple.x);\r
+            if (value != null && value >= nTimeout && tuple.y == BootstrapStatus.ONLINE) {\r
+                keepAliveMap.put(tuple.x, value - 1);\r
+                removedNeighbours.add(tuple);\r
+            } else {\r
+\r
+                if (tuple.y == BootstrapStatus.ONLINE) {\r
+                    onlineNeighbours++;\r
+                }\r
+            }\r
+        }\r
+        neighbours.removeAll(removedNeighbours);\r
+\r
+        // Fix the neighbours number to the maximum allowed\r
+        SymphonyNodeComparator comparator = new SymphonyNodeComparator(symphonyID, node);\r
+        AdapterSymphonyNodeComparator adapterComparator = new AdapterSymphonyNodeComparator(comparator);\r
+        while (neighbours.size() > symphony.numberShortRangeLinksPerSide) {\r
+            Tuple<Node, BootstrapStatus> distantTuple = Collections.max(neighbours, adapterComparator);\r
+\r
+            // Mantain the link with the ring\r
+            if (distantTuple.y == BootstrapStatus.ONLINE) {\r
+                if (onlineNeighbours > 1) {\r
+                    neighbours.remove(distantTuple);\r
+                    onlineNeighbours--;\r
+                } else {\r
+                    /*\r
+                     * If will be only one neighbour that is online i save it and i'm going to\r
+                     * eliminate another one (for sure it'll be not online)\r
+                     *\r
+                     */\r
+                    Tuple<Node, BootstrapStatus> backupOnlineNeighbour = distantTuple;\r
+                    neighbours.remove(backupOnlineNeighbour);\r
+                    distantTuple = Collections.max(neighbours, adapterComparator);\r
+                    neighbours.add(backupOnlineNeighbour);\r
+                    neighbours.remove(distantTuple);\r
+                }\r
+\r
+            } else {\r
+                neighbours.remove(distantTuple);\r
+            }\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Object clone() {\r
+        SymphonyNetworkManager dolly = new SymphonyNetworkManager(prefix);\r
+        return dolly;\r
+    }\r
+\r
+    public void nextCycle(Node node, int protocolID) {\r
+\r
+        if (node.isUp()) {\r
+\r
+            // Update the estimated network size\r
+            updateN(node);\r
+\r
+            // Update the estimated K\r
+            updateK(node);\r
+\r
+            // Update the bootstrap status of my neighbours that were joining the ring\r
+            updateBootstrapStatusNeighbours(node, false);\r
+\r
+            // Refresh the neighbours views\r
+            refreshNeighbours(node);\r
+\r
+            // I send and check the connection status of the neighbours\r
+            keepAlive(node);\r
+\r
+            // Update the bootstrap status\r
+            checkBootstrapStatus(node);\r
+\r
+            // If it's active i check the Relinking criteria\r
+            if (relinkingProtocolActivated) {\r
+                reLinkingProtocol(node);\r
+            }\r
+\r
+            // Update the long range links (conservative)\r
+            updateLongRangeLinks(node);\r
+        }\r
+    }\r
+\r
+    /**\r
+     *\r
+     * @param allNeighbours true, communicate/receive the status update from all the neighbours.\r
+     * false, communicate/receive the status update only from the neighbours that are NOT ONLINE\r
+     *\r
+     */\r
+    private void updateBootstrapStatusNeighbours(Node node, boolean allNeighbours) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+        Collection<Tuple<Node, BootstrapStatus>> collection = new LinkedHashSet<Tuple<Node, BootstrapStatus>>();\r
+        collection.addAll(symphony.leftShortRangeLinks);\r
+        collection.addAll(symphony.rightShortRangeLinks);\r
+\r
+        for (Tuple<Node, BootstrapStatus> neighbourTuple : collection) {\r
+            if (allNeighbours || neighbourTuple.y != BootstrapStatus.ONLINE) {\r
+                Message msg = new Message(symphony.loggedIntoNetwork, node, MessageType.UPDATE_STATUS);\r
+                transport.send(node, neighbourTuple.x, msg, pid);\r
+            }\r
+        }\r
+    }\r
+\r
+    private void updateN(Node node) {\r
+        NetworkSizeEstimatorProtocolInterface networkEstimator = (NetworkSizeEstimatorProtocolInterface) node.getProtocol(networkEstimatorID);\r
+        n = networkEstimator.getNetworkSize(node);\r
+        if (n <= 0) {\r
+            n = DEFAULT_N;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Update the K value with the current expectation of the network size\r
+     */\r
+    private void updateK(Node node) {\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        if (!symphony.fixedLongRangeLinks) {\r
+            k = (int) Math.ceil(Math.log(n) / Math.log(2));\r
+\r
+            if (k <= 0) {\r
+                k = DEFAULT_K;\r
+            }\r
+        } else {\r
+            k = symphony.numberFixedLongRangeLinks;\r
+        }\r
+    }\r
+\r
+    private void refreshNeighbours(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+        for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+            Node leftNode = leftTuple.x;\r
+            Message updateNeighbourMsg = new Message(symphony.loggedIntoNetwork, node, MessageType.UPDATE_NEIGHBOURS);\r
+            transport.send(node, leftNode, updateNeighbourMsg, pid);\r
+        }\r
+\r
+        for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+            Node rightNode = rightTuple.x;\r
+            Message updateNeighbourMsg = new Message(symphony.loggedIntoNetwork, node, MessageType.UPDATE_NEIGHBOURS);\r
+            transport.send(node, rightNode, updateNeighbourMsg, pid);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Method to update the (connection) status of the node. Perform the update to the "up" so:\r
+     * OFFLINE -> ONLINE_AND_ALL_NEIGHBOURS_OFFLINE -> ONLINE\r
+     *\r
+     * and to the "down" only: ONLINE -> ONLINE_AND_ALL_NEIGHBOURS_OFFLINE\r
+     *\r
+     * @param node\r
+     */\r
+    private void checkBootstrapStatus(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+        if (symphony.loggedIntoNetwork != BootstrapStatus.OFFLINE) {\r
+\r
+            symphony.loggedIntoNetwork = BootstrapStatus.ONLINE_AND_ALL_NEIGHBOURS_OFFLINE;\r
+\r
+            // Check if i'm inside the ring and i'm able to do routing\r
+            if (!symphony.leftShortRangeLinks.isEmpty() && !symphony.rightShortRangeLinks.isEmpty()) {\r
+\r
+                boolean leftOk = false;\r
+                for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+                    if (leftTuple.y == BootstrapStatus.ONLINE) {\r
+                        leftOk = true;\r
+                        break;\r
+                    }\r
+                }\r
+\r
+                if (leftOk) {\r
+                    for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+                        if (rightTuple.y == BootstrapStatus.ONLINE) {\r
+                            symphony.loggedIntoNetwork = BootstrapStatus.ONLINE;\r
+                            break;\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Remove the possible wrong entries from the lookAhead table\r
+     */\r
+    private void fixLookAheadMap(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        for (Tuple<Node, BootstrapStatus> tuple : symphony.leftShortRangeLinks) {\r
+            symphony.lookAheadMap.put(tuple.x, null);\r
+        }\r
+        for (Tuple<Node, BootstrapStatus> tuple : symphony.rightShortRangeLinks) {\r
+            symphony.lookAheadMap.put(tuple.x, null);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Sent keep-alive messages to verify if the links still online\r
+     *\r
+     * if enable the lookAhead mode i require the neighbours list from my neighbours (1-lookAhead).\r
+     *\r
+     * Note: I don't reuse the UPDATE_STATUS messages because i want to mantain separate the\r
+     * semantic and have more clear source code\r
+     */\r
+    private void keepAlive(Node node) {\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+        // Send and check for the long range links (both incoming and outgoing)\r
+        for (Iterable<Node> iterable : new Iterable[]{symphony.longRangeLinksOutgoing, symphony.longRangeLinksIncoming}) {\r
+            Iterator<Node> longLinksIterator = iterable.iterator();\r
+            while (longLinksIterator.hasNext()) {\r
+                Node longLinkNode = longLinksIterator.next();\r
+                Integer value = keepAliveMap.get(longLinkNode);\r
+                if (value == null) {\r
+                    value = 0;\r
+                }\r
+\r
+                /*\r
+                 * Verify if i reached the sufficient time of sending and not receiving an answer\r
+                 * and so i can consider that node as disconnected\r
+                 */\r
+                if (value >= nTimeout) {\r
+                    symphony.lookAheadMap.put(longLinkNode, null); // Do it anyway if it's enabled the lookAhead or not\r
+                    longLinksIterator.remove();\r
+                } else {\r
+                    keepAliveMap.put(longLinkNode, value + 1);\r
+\r
+                    Message keepAliveMsg = new Message(symphony.lookAhead, node, MessageType.KEEP_ALIVE);\r
+                    transport.send(node, longLinkNode, keepAliveMsg, pid);\r
+                }\r
+            }\r
+        }\r
+\r
+        // Send and check for the short links\r
+        for (Iterable<Tuple<Node, BootstrapStatus>> iterable : new Iterable[]{symphony.rightShortRangeLinks, symphony.leftShortRangeLinks}) {\r
+            Iterator<Tuple<Node, BootstrapStatus>> shortLinksIterator = iterable.iterator();\r
+            while (shortLinksIterator.hasNext()) {\r
+                Node shortLinkNode = shortLinksIterator.next().x;\r
+                Integer value = keepAliveMap.get(shortLinkNode);\r
+                if (value == null) {\r
+                    value = 0;\r
+                }\r
+\r
+                // the same as above\r
+                if (value >= nTimeout) {\r
+                    shortLinksIterator.remove();\r
+                } else {\r
+                    keepAliveMap.put(shortLinkNode, value + 1);\r
+\r
+                    // LookAhead is not to be performed to the short links!\r
+                    Message keepAliveMsg = new Message(false, node, MessageType.KEEP_ALIVE);\r
+                    transport.send(node, shortLinkNode, keepAliveMsg, pid);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Implement the Re-Linking criteria of the Long Range Links. It does the complete refresh. The\r
+     * repopulation is done through the 'updateLongRangeLinks' method.\r
+     */\r
+    private void reLinkingProtocol(Node node) {\r
+        // I do the check only if i succeed at least one time to create a long range link\r
+        if (nLink > 0) {\r
+            double criterionValue = n / nLink;\r
+\r
+            if (!(criterionValue >= relinkingLowerBound && criterionValue <= relinkingUpperBound)) {\r
+\r
+                /*\r
+                 * Not explicitly precised in the paper: if i haven't created a new link i update\r
+                 * anyway nLink because can happen a special case that i will not be able to create\r
+                 * links because the reLinkingProtocol procedure is "faster".\r
+                 */\r
+                nLink = n;\r
+\r
+                SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+                Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+                // Communicate to the all Outgoing Long Range Links that they aren't anymore\r
+                for (Node longRangeLinkOutgoingNode : symphony.longRangeLinksOutgoing) {\r
+                    Message disconnectMsg = new Message(null, node, MessageType.DISCONNECT_LONG_RANGE_LINK);\r
+                    transport.send(node, longRangeLinkOutgoingNode, disconnectMsg, pid);\r
+                }\r
+\r
+                symphony.longRangeLinksOutgoing.clear();\r
+            }\r
+        }\r
+    }\r
+\r
+    public int getK() {\r
+        return k;\r
+    }\r
+\r
+    public int getN() {\r
+        return n;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyNodeComparator.java b/contrib/psg/src/example/symphony/SymphonyNodeComparator.java
new file mode 100644 (file)
index 0000000..e5a17d2
--- /dev/null
@@ -0,0 +1,51 @@
+package example.symphony;\r
+\r
+import java.util.Comparator;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ * Comparator that measure the relative distance from a target node\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyNodeComparator implements Comparator<Node> {\r
+\r
+    private final int symphonyID;\r
+    private double target;\r
+\r
+    public SymphonyNodeComparator(int symphonyID) {\r
+        this.symphonyID = symphonyID;\r
+    }\r
+\r
+    public SymphonyNodeComparator(int symphonyID, double target) {\r
+        this(symphonyID);\r
+        this.target = target;\r
+    }\r
+\r
+    public SymphonyNodeComparator(int symphonyID, Node targetNode) {\r
+        this(symphonyID);\r
+        SymphonyProtocol symphony = (SymphonyProtocol) targetNode.getProtocol(symphonyID);\r
+        this.target = symphony.getIdentifier();\r
+    }\r
+\r
+    public int compare(Node o1, Node o2) {\r
+\r
+        SymphonyProtocol symphony1 = (SymphonyProtocol) o1.getProtocol(symphonyID);\r
+        SymphonyProtocol symphony2 = (SymphonyProtocol) o2.getProtocol(symphonyID);\r
+\r
+        Double identifier1 = symphony1.getIdentifier();\r
+        Double identifier2 = symphony2.getIdentifier();\r
+\r
+        Double distance1 = Math.abs(target - identifier1) % 1;\r
+        Double distance2 = Math.abs(target - identifier2) % 1;\r
+\r
+        identifier1 = Math.min(1.0 - distance1, distance1);\r
+        identifier2 = Math.min(1.0 - distance2, distance2);\r
+\r
+        Logger.getLogger(SymphonyNodeComparator.class.getName()).log(Level.FINEST, "id1= " + symphony1.getIdentifier() + " target= " + target + " id2= " + symphony2.getIdentifier() + " res= " + identifier1.compareTo(identifier2));\r
+\r
+        return identifier1.compareTo(identifier2);\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyNodeInizializer.java b/contrib/psg/src/example/symphony/SymphonyNodeInizializer.java
new file mode 100644 (file)
index 0000000..ec5dc68
--- /dev/null
@@ -0,0 +1,59 @@
+package example.symphony;\r
+\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+import peersim.config.Configuration;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+import peersim.dynamics.NodeInitializer;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyNodeInizializer implements NodeInitializer {\r
+\r
+    private static final String PAR_NETMANAGER = "symphonynetworkmanager";\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private static final String PAR_BOOTNODE = "bootstrapnode";\r
+    private final int networkManagerID;\r
+    private final int symphonyID;\r
+    private final int indexBootstrapNode;\r
+\r
+    public SymphonyNodeInizializer(String prefix) {\r
+\r
+        networkManagerID = Configuration.getPid(prefix + "." + PAR_NETMANAGER);\r
+        indexBootstrapNode = Configuration.getInt(prefix + "." + PAR_BOOTNODE, 0);\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+    }\r
+\r
+    @Override\r
+    public void initialize(Node node) {\r
+        int indexRealBootstrapNode = indexBootstrapNode;\r
+        Node realBootstrapNode = Network.get(indexBootstrapNode);\r
+        SymphonyNetworkManager symphonyNetworkManager = (SymphonyNetworkManager) node.getProtocol(networkManagerID);\r
+        SymphonyProtocol symphony = (SymphonyProtocol) realBootstrapNode.getProtocol(symphonyID);\r
+\r
+        boolean joinSent;\r
+        do {\r
+            try {\r
+                while (!symphony.isBootstrapped() || !realBootstrapNode.isUp()) {\r
+                    indexRealBootstrapNode = (indexRealBootstrapNode + 1) % Network.size();\r
+                    realBootstrapNode = Network.get(indexRealBootstrapNode);\r
+                    symphony = (SymphonyProtocol) realBootstrapNode.getProtocol(symphonyID);\r
+\r
+                    if (indexRealBootstrapNode == indexBootstrapNode) {\r
+                        Logger.getLogger(SymphonyNodeInizializer.class.getName()).log(Level.WARNING, "No node ONLINE. Impossible to do the network bootstrap.");\r
+                        return;\r
+                    }\r
+                }\r
+\r
+                symphonyNetworkManager.join(node, realBootstrapNode);\r
+                joinSent = true;\r
+            } catch (RoutingException ex) {\r
+                Logger.getLogger(SymphonyNodeInizializer.class.getName()).log(Level.SEVERE, "Join Issue");\r
+                joinSent = false;\r
+            }\r
+        } while (!joinSent);\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyProtocol.java b/contrib/psg/src/example/symphony/SymphonyProtocol.java
new file mode 100644 (file)
index 0000000..478f81e
--- /dev/null
@@ -0,0 +1,530 @@
+package example.symphony;\r
+\r
+import java.lang.ref.SoftReference;\r
+import java.util.*;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import example.symphony.Message.MessageType;\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Node;\r
+import peersim.edsim.EDProtocol;\r
+import peersim.transport.Transport;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyProtocol implements EDProtocol {\r
+\r
+    private static final String PAR_SHORT_LINK = "shortlink";\r
+    private static final String PAR_LONG_LINK = "longlink";\r
+    private static final String PAR_TRANSP = "transport";\r
+    private static final String PAR_ROUTING = "routing";\r
+    private static final String PAR_LOOKAHEAD = "lookahead";\r
+    private static Set<Double> allIdentifier = new HashSet<Double>();\r
+    private final String prefix;\r
+    private static int pid;\r
+    private final int transportID;\r
+    private final double identifier;\r
+    public final int sequentialIdentifier;\r
+    private static int sequentialCounter = 0;\r
+    public final int numberShortRangeLinksPerSide;\r
+    public final boolean bidirectionalRouting;\r
+    public final boolean lookAhead;\r
+    public final boolean fixedLongRangeLinks;\r
+    public final int numberFixedLongRangeLinks;\r
+    public LinkedHashSet<Node> longRangeLinksOutgoing;\r
+    public LinkedHashSet<Node> longRangeLinksIncoming;\r
+    public LinkedHashSet<Tuple<Node, BootstrapStatus>> rightShortRangeLinks;\r
+    public LinkedHashSet<Tuple<Node, BootstrapStatus>> leftShortRangeLinks;\r
+    /**\r
+     * Array Contract: at position 0 -> OutgoingLongRangeLinks, 1 -> IncomingLongRangeLinks\r
+     */\r
+    public final LinkedHashMap<Node, Set<Double>[]> lookAheadMap;\r
+    private HashMap<Double, Handler> mapHandler;\r
+    /**\r
+     * IDs Set to verify if there are cycles\r
+     */\r
+    private Set<Long> messageHistoryID;\r
+    /**\r
+     *\r
+     * Tuple chronology that contains: <received message, the possible answer message>\r
+     *\r
+     * I use SoftReference as a trade off between memory usage and accurancy\r
+     */\r
+    private Set<SoftReference<Tuple<Message, Message>>> messageHistory;\r
+    private static boolean firstPrintConfig = true;\r
+\r
+    public enum BootstrapStatus {\r
+\r
+        NEW, OFFLINE, ONLINE_AND_ALL_NEIGHBOURS_OFFLINE, ONLINE\r
+    }\r
+    public BootstrapStatus loggedIntoNetwork;\r
+\r
+    public SymphonyProtocol(String prefix) {\r
+\r
+        this.prefix = prefix;\r
+        pid = Configuration.lookupPid(prefix.replaceAll("protocol.", ""));\r
+        transportID = Configuration.getPid(prefix + "." + PAR_TRANSP);\r
+        numberShortRangeLinksPerSide = Configuration.getInt(prefix + "." + PAR_SHORT_LINK, 2) / 2;\r
+        bidirectionalRouting = !Configuration.getString(prefix + "." + PAR_ROUTING, "bidirectional").toLowerCase().equals("unidirectional");\r
+        lookAhead = !Configuration.getString(prefix + "." + PAR_LOOKAHEAD, "on").toLowerCase().equals("off");\r
+        numberFixedLongRangeLinks = Configuration.getInt(prefix + "." + PAR_LONG_LINK, -1);\r
+        fixedLongRangeLinks = numberFixedLongRangeLinks >= 0;\r
+\r
+        longRangeLinksOutgoing = new LinkedHashSet<Node>();\r
+        longRangeLinksIncoming = new LinkedHashSet<Node>();\r
+        rightShortRangeLinks = new LinkedHashSet<Tuple<Node, BootstrapStatus>>();\r
+        leftShortRangeLinks = new LinkedHashSet<Tuple<Node, BootstrapStatus>>();\r
+        lookAheadMap = new LinkedHashMap<Node, Set<Double>[]>();\r
+\r
+        identifier = generateUniqueIdentifier();\r
+        sequentialIdentifier = sequentialCounter++;\r
+\r
+        mapHandler = new HashMap<Double, Handler>();\r
+\r
+        messageHistoryID = new HashSet<Long>();\r
+        messageHistory = new LinkedHashSet<SoftReference<Tuple<Message, Message>>>();\r
+        loggedIntoNetwork = BootstrapStatus.NEW;\r
+\r
+        printConfig();\r
+    }\r
+\r
+    private void printConfig() {\r
+\r
+        if (firstPrintConfig) {\r
+            firstPrintConfig = false;\r
+            System.out.println(SymphonyProtocol.class.getSimpleName() + " Configuration:");\r
+            System.out.println("- Number of short range links per side: " + numberShortRangeLinksPerSide);\r
+            System.out.println("- Number of long range links: " + (fixedLongRangeLinks ? numberFixedLongRangeLinks : "log(n)"));\r
+            System.out.println("- Routing mode: " + (bidirectionalRouting ? "Bidirectional" : "Unidirectional"));\r
+            System.out.println("- LookAhead status: " + (lookAhead ? "ON" : "OFF"));\r
+            System.out.println("-------------------------------\n");\r
+        }\r
+    }\r
+\r
+    /**\r
+     *\r
+     * Method to identify the next node that has to be contacted. It's going to be used the mode\r
+     * that is described into the configuration file\r
+     */\r
+    public Node getCandidateForRouting(double identifierToRoute) throws RoutingException {\r
+        if (bidirectionalRouting) {\r
+            return getCandidateForBidirectionalRoute(identifierToRoute);\r
+        } else {\r
+            return getCandidateForUnidirectionalRoute(identifierToRoute);\r
+        }\r
+    }\r
+\r
+    /**\r
+     *\r
+     * Method to individuate the next node that as to be contacted through Unidirectional Routing\r
+     * mode\r
+     */\r
+    public Node getCandidateForUnidirectionalRoute(double identifierToRoute) throws RoutingException {\r
+\r
+        LinkedHashSet<Node> allLinks = new LinkedHashSet<Node>();\r
+        Node manager = putShortRangeLinksIntoContainerForRouting(allLinks, identifierToRoute);\r
+\r
+        if (manager != null) {\r
+            return manager;\r
+        }\r
+\r
+        allLinks.addAll(longRangeLinksOutgoing);\r
+\r
+        return findClosestNode(identifierToRoute, allLinks, true);\r
+    }\r
+\r
+    /**\r
+     * Method to individuate the next node that as to be contacted through Bidirectional Routing\r
+     * mode\r
+     */\r
+    public Node getCandidateForBidirectionalRoute(double identifierToRoute) throws RoutingException {\r
+\r
+        LinkedHashSet<Node> allLinks = new LinkedHashSet<Node>();\r
+        Node manager = putShortRangeLinksIntoContainerForRouting(allLinks, identifierToRoute);\r
+\r
+        if (manager != null) {\r
+            return manager;\r
+        }\r
+\r
+        allLinks.addAll(longRangeLinksOutgoing);\r
+        allLinks.addAll(longRangeLinksIncoming);\r
+\r
+        return findClosestNode(identifierToRoute, allLinks, false);\r
+    }\r
+\r
+    /**\r
+     * @return Null if it is NOT found the manager. Node if it is found.\r
+     */\r
+    private Node putShortRangeLinksIntoContainerForRouting(Set<Node> container, double identifierToRoute) {\r
+        for (Tuple<Node, BootstrapStatus> rightTuple : rightShortRangeLinks) {\r
+            if (rightTuple.y == BootstrapStatus.ONLINE) {\r
+                container.add(rightTuple.x);\r
+            }\r
+        }\r
+\r
+        if (!container.isEmpty()) {\r
+\r
+            // Special case: i verify if the neighbour at my right (ONLINE) is the manager\r
+            SymphonyNodeComparator comparator = new SymphonyNodeComparator(pid, identifier);\r
+            Node nearRightNeighbour = Collections.min(container, comparator);\r
+            if (nearRightNeighbour != null) {\r
+                SymphonyProtocol symphony = (SymphonyProtocol) nearRightNeighbour.getProtocol(pid);\r
+                if (!isLeftNeighbour(identifier, identifierToRoute) && isLeftNeighbour(symphony.getIdentifier(), identifierToRoute)) {\r
+                    return nearRightNeighbour;\r
+                }\r
+            }\r
+        }\r
+\r
+        for (Tuple<Node, BootstrapStatus> leftTuple : leftShortRangeLinks) {\r
+            if (leftTuple.y == BootstrapStatus.ONLINE) {\r
+                container.add(leftTuple.x);\r
+            }\r
+        }\r
+\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     *\r
+     * Individuates effectively the next candidate for the routing. Checks if the lookahead is\r
+     * activated and in case of affirmative answer it's going to use that information.\r
+     *\r
+     * @param identifierToRoute Identifier to reach\r
+     * @param container Candidate Nodes Container\r
+     * @param clockwise true, does unidirectional routing. false, does bidirectional routing.\r
+     * @return The nearest node to reach identifierToRoute\r
+     * @throws RoutingException Throw in case no candidate is found\r
+     */\r
+    public Node findClosestNode(final double identifierToRoute, final Iterable<Node> container, final boolean clockwise) throws RoutingException {\r
+        Node ret = null;\r
+        double min = Double.MAX_VALUE;\r
+\r
+        for (Node node : container) {\r
+            SymphonyProtocol symphonyNodeContainer = (SymphonyProtocol) node.getProtocol(pid);\r
+            double realCandidateIdentifier = symphonyNodeContainer.getIdentifier();\r
+\r
+            Set<Double> candidateIdentifierSet = new LinkedHashSet<Double>();\r
+            candidateIdentifierSet.add(realCandidateIdentifier);\r
+\r
+            boolean lookAheadClockwise = true;\r
+\r
+            /*\r
+             *\r
+             * If lookahead is activated add all the reachable identifiers. No checks are performed\r
+             * on the node type (short/long) because at maximum the map return null.\r
+             */\r
+            if (lookAhead) {\r
+                Set<Double>[] lookAheadIdentifierSetArray = lookAheadMap.get(node);\r
+\r
+                if (lookAheadIdentifierSetArray != null) {\r
+                    Set<Double> lookAheadIdentifierSet = lookAheadIdentifierSetArray[0];\r
+\r
+                    if (lookAheadIdentifierSet == null) {\r
+                        lookAheadIdentifierSet = new LinkedHashSet<Double>();\r
+                    }\r
+\r
+                    /*\r
+                     *\r
+                     * If bidirectional routing is going to be performed so i put into account also\r
+                     * the Incoming Long Range Links of the current neighbour\r
+                     */\r
+                    if (bidirectionalRouting && lookAheadIdentifierSetArray[1] != null) {\r
+                        lookAheadIdentifierSet.addAll(lookAheadIdentifierSetArray[1]);\r
+                        lookAheadClockwise = false;\r
+                    }\r
+\r
+                    if (!lookAheadIdentifierSet.isEmpty()) {\r
+                        candidateIdentifierSet.addAll(lookAheadIdentifierSet);\r
+                    }\r
+                }\r
+            }\r
+\r
+            for (Double candidateIdentifier : candidateIdentifierSet) {\r
+                // if it is a my neighbour i use my routing mode instead if it is a looAhead one i use its routing mode\r
+                boolean currentClockwise = candidateIdentifier.equals(realCandidateIdentifier) ? clockwise : lookAheadClockwise;\r
+\r
+                double distance = Math.abs(candidateIdentifier - identifierToRoute);\r
+                distance = Math.min(distance, 1.0 - distance);\r
+\r
+                // if clockwise i have to exclude the case: candidateIdentifier - indentifierToRoute - identifier\r
+                if (currentClockwise) {\r
+                    if (isLeftNeighbour(candidateIdentifier, identifierToRoute)) {\r
+\r
+                        // Special case (0.9 - 0.1) the normal order is not more meanful to decide the side\r
+                        if (identifierToRoute >= candidateIdentifier) {\r
+                            distance = identifierToRoute - candidateIdentifier;\r
+                        } else {\r
+                            distance = (1.0 - candidateIdentifier) + identifierToRoute;\r
+                        }\r
+                    } else {\r
+                        distance = (1.0 - (candidateIdentifier - identifierToRoute)) % 1;\r
+                    }\r
+                }\r
+\r
+                /*\r
+                 *\r
+                 * Priority to the node that i'm directly connected and only after i use the\r
+                 * lookAhead information\r
+                 */\r
+                if (min >= Math.abs(distance)\r
+                        && (candidateIdentifier.equals(realCandidateIdentifier)\r
+                        || ret == null\r
+                        || min > Math.abs(distance))) {\r
+                    ret = node;\r
+                    min = Math.abs(distance);\r
+                }\r
+            }\r
+        }\r
+\r
+        if (ret == null) {\r
+            throw new RoutingException("Impossible do routing. [Hit: Neighbour links (maybe) not yet online.");\r
+        }\r
+\r
+        return ret;\r
+    }\r
+\r
+    /**\r
+     *\r
+     * @param neighbourNode Neighbour Node\r
+     * @return true if the node is a left neighbour (or itself), false if it is a right one\r
+     */\r
+    public static boolean isLeftNeighbour(Node rootNode, Node neighbourNode) {\r
+        SymphonyProtocol rootSymphony = (SymphonyProtocol) rootNode.getProtocol(pid);\r
+        SymphonyProtocol neighbourSymphony = (SymphonyProtocol) neighbourNode.getProtocol(pid);\r
+\r
+        return isLeftNeighbour(rootSymphony.getIdentifier(), neighbourSymphony.getIdentifier());\r
+    }\r
+\r
+    public static boolean isLeftNeighbour(double rootIdentifier, double neighbourIdentifier) {\r
+\r
+        // I calculate putting the hypotesis that i have to translate/"normalize", after i'll check if it was useless\r
+        double traslateRootIdentifier = (rootIdentifier + 0.5) % 1;\r
+        double traslateNeighbourIdentifier = (neighbourIdentifier + 0.5) % 1;\r
+        double distance = traslateNeighbourIdentifier - traslateRootIdentifier;\r
+\r
+        // I verify if the neighbourIdentifier is over half ring, if yes i don't need to do the translation/"normalization"\r
+        if ((neighbourIdentifier + 0.5) != traslateNeighbourIdentifier) {\r
+            distance = neighbourIdentifier - rootIdentifier;\r
+        }\r
+\r
+        return distance >= 0 && distance <= 0.5;\r
+    }\r
+\r
+    public void route(Node src, double key, Handler handler) throws RoutingException {\r
+\r
+        mapHandler.put(key, handler);\r
+\r
+        Message msg = new Message(key, src, MessageType.ROUTE);\r
+\r
+        Node targetNode = src;\r
+\r
+        if (!isManagerOf(key)) {\r
+            targetNode = getCandidateForRouting(key);\r
+            Transport transport = (Transport) src.getProtocol(transportID);\r
+            transport.send(src, targetNode, msg, pid);\r
+        }\r
+\r
+        // Insert the message into the chronology\r
+        Tuple<Message, Message> historyTuple = new Tuple<Message, Message>();\r
+        try {\r
+            historyTuple.x = msg;\r
+            historyTuple.y = (Message) msg.clone();\r
+            historyTuple.y.setCurrentHop(targetNode);\r
+        } catch (CloneNotSupportedException ex) {\r
+            Logger.getLogger(SymphonyProtocol.class.getName()).log(Level.SEVERE, "Impossible to clonate the message!");\r
+            historyTuple.x = null;\r
+            historyTuple.y = msg;\r
+            msg.setCurrentHop(targetNode);\r
+        }\r
+        messageHistory.add(new SoftReference<Tuple<Message, Message>>(historyTuple));\r
+        messageHistoryID.add(msg.getID());\r
+\r
+        /*\r
+         *\r
+         * If i am the manager (brutally through the reference), i don't do the loopback routing but\r
+         * i soddisfy immediately the request\r
+         */\r
+        if (targetNode == src) {\r
+\r
+            // Uppdate the chronology\r
+            historyTuple.y = new Message(key, targetNode, MessageType.ROUTE_RESPONSE);\r
+\r
+            Tuple<Node, Double> tuple = new Tuple<Node, Double>(src, key);\r
+            mapHandler.remove(key);\r
+            handler.handle(this, tuple);\r
+        }\r
+    }\r
+\r
+    public void processEvent(Node node, int pid, Object event) {\r
+        Message msg = (Message) event;\r
+        msg.incrementHop(); // I increment the message Hop\r
+\r
+        Tuple<Message, Message> historyTuple = new Tuple<Message, Message>();\r
+        try {\r
+            // I clone the message such a way to store into the chronology the hop sender's information\r
+            historyTuple.x = (Message) msg.clone();\r
+        } catch (CloneNotSupportedException ex) {\r
+            Logger.getLogger(SymphonyProtocol.class.getName()).log(Level.SEVERE, "Impossible to clonate the message!");\r
+            historyTuple.x = msg;\r
+        }\r
+\r
+        messageHistory.add(new SoftReference<Tuple<Message, Message>>(historyTuple));\r
+\r
+        Double key;\r
+        Transport transport;\r
+        Handler handler;\r
+\r
+        // Individuate cycles\r
+        if (messageHistoryID.contains(msg.getID())) {\r
+            Message responseMsg = new Message(msg, node, MessageType.ROUTE_FAIL);\r
+\r
+            historyTuple.y = responseMsg;\r
+\r
+            transport = (Transport) node.getProtocol(transportID);\r
+            transport.send(node, msg.getSourceNode(), responseMsg, pid);\r
+            return;\r
+        }\r
+\r
+        /*\r
+         * If i'm arrived till here means that i'm not into a cycle --> i insert the message ID into\r
+         * the chronology\r
+         */\r
+        messageHistoryID.add(msg.getID());\r
+\r
+        switch (msg.getType()) {\r
+            case ROUTE:\r
+                key = (Double) msg.getBody();\r
+                Logger.getLogger(SymphonyProtocol.class.getName()).log(Level.FINEST, key + " " + identifier);\r
+                if (isManagerOf(key)) {\r
+                    transport = (Transport) msg.getSourceNode().getProtocol(transportID);\r
+                    Message responseMsg = new Message(new Tuple<Node, Double>(node, key), node, MessageType.ROUTE_RESPONSE);\r
+                    historyTuple.y = responseMsg;\r
+                    transport.send(node, msg.getSourceNode(), responseMsg, pid);\r
+                } else {\r
+                    try {\r
+                        Node targetNode = getCandidateForRouting(key);\r
+\r
+                        try {\r
+                            // I clone the message such a way to store the info (into the chronology) of the hop receiver\r
+                            historyTuple.y = (Message) msg.clone();\r
+                            historyTuple.y.setCurrentHop(targetNode);\r
+                        } catch (CloneNotSupportedException ex) {\r
+                            Logger.getLogger(SymphonyProtocol.class.getName()).log(Level.SEVERE, "Impossible to clonate the message!");\r
+                            historyTuple.y = msg;\r
+                            msg.setCurrentHop(targetNode);\r
+                        }\r
+\r
+                        transport = (Transport) node.getProtocol(transportID);\r
+                        transport.send(node, targetNode, msg, pid);\r
+                    } catch (RoutingException ex) {\r
+                        /*\r
+                         *\r
+                         * I send the same message to myself (it is going to queue into the event\r
+                         * queue and in this way i "earn" time (postpone) and i hope that the\r
+                         * network will be ok in the meanwhile)\r
+                         */\r
+                        historyTuple.y = msg;\r
+                        msg.setCurrentHop(node);\r
+                        transport = (Transport) node.getProtocol(transportID);\r
+                        transport.send(node, node, msg, pid);\r
+                    }\r
+                }\r
+                break;\r
+            case ROUTE_RESPONSE:\r
+                Tuple<Node, Double> tuple = (Tuple<Node, Double>) msg.getBody();\r
+                key = tuple.y;\r
+                handler = mapHandler.get(key);\r
+                mapHandler.remove(key);\r
+                handler.handle(this, tuple);\r
+                break;\r
+            case ROUTE_FAIL:\r
+                Message requestMsg = (Message) msg.getBody();\r
+                key = (Double) requestMsg.getBody();\r
+                handler = mapHandler.get(key);\r
+                mapHandler.remove(key);\r
+                handler.handle(this, null);\r
+                break;\r
+        }\r
+    }\r
+\r
+    public boolean isManagerOf(double key) {\r
+\r
+        if (key == identifier) {\r
+            return true;\r
+        }\r
+\r
+        SymphonyNodeComparator comparator = new SymphonyNodeComparator(pid, identifier);\r
+        AdapterSymphonyNodeComparator adapterComparator = new AdapterSymphonyNodeComparator(comparator);\r
+\r
+        Collection<Tuple<Node, BootstrapStatus>> leftShortRangeLinksCloned = (Collection<Tuple<Node, BootstrapStatus>>) leftShortRangeLinks.clone();\r
+        Node targetNode = null;\r
+\r
+        while (targetNode == null && !leftShortRangeLinksCloned.isEmpty()) {\r
+            Tuple<Node, BootstrapStatus> nearTuple = Collections.min(leftShortRangeLinksCloned, adapterComparator);\r
+            if (nearTuple.y == BootstrapStatus.ONLINE) {\r
+                targetNode = nearTuple.x;\r
+            } else {\r
+                leftShortRangeLinksCloned.remove(nearTuple);\r
+            }\r
+        }\r
+\r
+        // SPECIAL CASE: NO LEFT NEIGHBOURS. I became the Manager.\r
+        if (targetNode == null) {\r
+            return true;\r
+        }\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) targetNode.getProtocol(pid);\r
+        // Check if it's the situation: right neighbour - key - me. So if i'm the manager or not.\r
+        boolean ret = isLeftNeighbour(identifier, key) && (!isLeftNeighbour(symphony.getIdentifier(), key) && symphony.getIdentifier() != key);\r
+\r
+        return ret;\r
+    }\r
+\r
+    public double getIdentifier() {\r
+        return identifier;\r
+    }\r
+\r
+    public Tuple<Message, Message>[] getHistoryMessage() {\r
+        SoftReference<Tuple<Message, Message>>[] array = messageHistory.toArray(new SoftReference[0]);\r
+        LinkedList<Tuple<Message, Message>> list = new LinkedList<Tuple<Message, Message>>();\r
+        for (SoftReference<Tuple<Message, Message>> reference : array) {\r
+            Tuple<Message, Message> tuple = reference.get();\r
+            if (tuple != null) {\r
+                list.add(tuple);\r
+            }\r
+        }\r
+        return list.toArray(new Tuple[0]);\r
+    }\r
+\r
+    public void clearHistoryMessage() {\r
+        messageHistory.clear();\r
+    }\r
+\r
+    private double generateUniqueIdentifier() {\r
+        boolean duplicated = true;\r
+        Double id = null;\r
+\r
+        while (duplicated) {\r
+            id = CommonState.r.nextDouble();\r
+            duplicated = allIdentifier.contains(id);\r
+        }\r
+\r
+        allIdentifier.add(id);\r
+\r
+        return id;\r
+    }\r
+\r
+    @Override\r
+    public Object clone() {\r
+        SymphonyProtocol dolly = new SymphonyProtocol(prefix);\r
+        return dolly;\r
+    }\r
+\r
+    public boolean isBootstrapped() {\r
+        return loggedIntoNetwork == BootstrapStatus.ONLINE;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyStatistics.java b/contrib/psg/src/example/symphony/SymphonyStatistics.java
new file mode 100644 (file)
index 0000000..4e97219
--- /dev/null
@@ -0,0 +1,77 @@
+package example.symphony;\r
+\r
+import peersim.config.Configuration;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyStatistics implements Control {\r
+\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private final int symphonyID;\r
+    private long totalMsg = 0;\r
+    private long numRouteResposeMsg = 0;\r
+    private long numRouteMsg = 0;\r
+    private long numRouteFailMsg = 0;\r
+    private long numRouteFoundManagerMsg = 0;\r
+    private double mediaHopRouteResponseMsg = 0.0;\r
+\r
+    public SymphonyStatistics(String prefix) {\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        AdapterIterableNetwork itNetwork = new AdapterIterableNetwork();\r
+        for (Node node : itNetwork) {\r
+            SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+            Tuple<Message, Message>[] tupleMessages = symphony.getHistoryMessage();\r
+            totalMsg += tupleMessages.length;\r
+\r
+            for (Tuple<Message, Message> tupleMessage : tupleMessages) {\r
+\r
+                Message message = tupleMessage.x;\r
+\r
+                if (message != null) {\r
+                    switch (message.getType()) {\r
+                        case ROUTE:\r
+                            numRouteMsg++;\r
+                            if (tupleMessage.y != null && tupleMessage.y.getType() == Message.MessageType.ROUTE_RESPONSE) {\r
+                                numRouteFoundManagerMsg++;\r
+                                mediaHopRouteResponseMsg = ((mediaHopRouteResponseMsg * (numRouteFoundManagerMsg - 1)) + message.getHop()) / (double) numRouteFoundManagerMsg;\r
+                            }\r
+                            break;\r
+                        case ROUTE_FAIL:\r
+                            numRouteFailMsg++;\r
+                            break;\r
+                        case ROUTE_RESPONSE:\r
+                            numRouteResposeMsg++;\r
+                            break;\r
+                    }\r
+                }\r
+            }\r
+\r
+            symphony.clearHistoryMessage();\r
+        }\r
+\r
+        printStatistics();\r
+\r
+        return false;\r
+    }\r
+\r
+    private void printStatistics() {\r
+        System.out.println("### Statistics ###");\r
+        System.out.println("- Total Messages: " + totalMsg);\r
+        System.out.println("- Total Route Messages: " + numRouteMsg);\r
+        System.out.println("- Found Manager Route Message: " + numRouteFoundManagerMsg);\r
+        System.out.println("- Response Message: " + numRouteResposeMsg);\r
+        System.out.println("- Fail Message: " + numRouteFailMsg);\r
+        System.out.println();\r
+        System.out.println("Average Hop:" + mediaHopRouteResponseMsg + " Expected value (k = log n): " + (Math.log(Network.size()) / Math.log(2)));\r
+        System.out.println("### END ###\n");\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/Tuple.java b/contrib/psg/src/example/symphony/Tuple.java
new file mode 100644 (file)
index 0000000..ed82b64
--- /dev/null
@@ -0,0 +1,45 @@
+package example.symphony;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class Tuple<X, Y> {\r
+\r
+    public X x;\r
+    public Y y;\r
+\r
+    public Tuple() {\r
+    }\r
+\r
+    public Tuple(X x, Y y) {\r
+        this.x = x;\r
+        this.y = y;\r
+    }\r
+\r
+    @Override\r
+    public boolean equals(Object obj) {\r
+\r
+        if (obj instanceof Tuple) {\r
+            Tuple tuple = (Tuple) obj;\r
+\r
+            // (x != null && tuple.x != null) ==> (x==tuple.x || x.equals(tuple.x))\r
+            // x == null <==> tuple.x == null\r
+\r
+            boolean equalsX = (x == null && tuple.x == null) || ((x != null && tuple.x != null) && (x == tuple.x || x.equals(tuple.x)));\r
+            boolean equalsY = (y == null && tuple.y == null) || ((y != null && tuple.y != null) && (y == tuple.y || y.equals(tuple.y)));\r
+\r
+            return equalsX && equalsY;\r
+        }\r
+\r
+        return false;\r
+    }\r
+\r
+    @Override\r
+    public int hashCode() {\r
+        int hash = 5;\r
+        hash = 89 * hash + (this.x != null ? this.x.hashCode() : 0);\r
+        hash = 89 * hash + (this.y != null ? this.y.hashCode() : 0);\r
+        return hash;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/test/NetworkEstimationTest.java b/contrib/psg/src/example/symphony/test/NetworkEstimationTest.java
new file mode 100644 (file)
index 0000000..1d0d945
--- /dev/null
@@ -0,0 +1,52 @@
+package example.symphony.test;\r
+\r
+import example.symphony.AdapterIterableNetwork;\r
+import example.symphony.SymphonyNetworkManager;\r
+import example.symphony.SymphonyProtocol;\r
+import peersim.config.Configuration;\r
+import peersim.core.Control;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class NetworkEstimationTest implements Control {\r
+\r
+    private static final String PAR_NETMANAGER = "symphonynetworkmanager";\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private final int symphonyID;\r
+    private final int networkManagerID;\r
+\r
+    public NetworkEstimationTest(String prefix) {\r
+\r
+        networkManagerID = Configuration.getPid(prefix + "." + PAR_NETMANAGER);\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        AdapterIterableNetwork it = new AdapterIterableNetwork();\r
+        int max = Integer.MIN_VALUE;\r
+        int min = Integer.MAX_VALUE;\r
+        int sum = 0;\r
+        int total = 0;\r
+        for (Node node : it) {\r
+            if (node.isUp() && ((SymphonyProtocol) node.getProtocol(symphonyID)).isBootstrapped()) {\r
+                SymphonyNetworkManager networkManager = (SymphonyNetworkManager) node.getProtocol(networkManagerID);\r
+                int n = networkManager.getN();\r
+                min = n < min ? n : min;\r
+                max = n > max ? n : max;\r
+                sum += n;\r
+                total++;\r
+            }\r
+        }\r
+\r
+        System.out.println("Real Dimension: " + (Math.log(total) / Math.log(2)));\r
+        System.out.println("Average Estimated Dimension: " + (total == 0 ? "No Node online" : (Math.log((sum / total)) / Math.log(2))));\r
+        System.out.println("MAX: " + Math.log(max) / Math.log(2));\r
+        System.out.println("MIN: " + Math.log(min) / Math.log(2));\r
+\r
+        return false;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/peersim/Simulator.java b/contrib/psg/src/peersim/Simulator.java
new file mode 100644 (file)
index 0000000..97c7965
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim;
+
+import psgsim.PSGSimulator;
+
+import java.io.*;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.simgrid.msg.HostNotFoundException;
+import org.simgrid.msg.NativeException;
+
+import peersim.cdsim.*;
+import peersim.config.*;
+import peersim.core.*;
+import peersim.edsim.*;
+
+/**
+ * This is the main entry point to peersim. This class loads configuration and
+ * detects the simulation type. According to this, it invokes the appropriate
+ * simulator. The known simulators at this moment, along with the way to detect
+ * them are the following:
+ * <ul>
+ * <li>{@link CDSimulator}: if {@link CDSimulator#isConfigurationCycleDriven}
+ * returns true</li>
+ * <li>{@link EDSimulator}: if {@link EDSimulator#isConfigurationEventDriven}
+ * returns true</li>
+ * </ul>
+ * This list represents the order in which these alternatives are checked. That
+ * is, if more than one return true, then the first will be taken. Note that
+ * this class checks only for these clues and does not check if the
+ * configuration is consistent or valid.
+ * 
+ * @see #main
+ */
+public class Simulator {
+
+       // ========================== static constants ==========================
+       // ======================================================================
+       public static int nbreR = 0;
+       /** {@link CDSimulator} */
+       public static final int CDSIM = 0;
+
+       /** {@link EDSimulator} */
+       public static final int EDSIM = 1;
+
+       /** {@link psgsim.PSGSimulator} */
+       public static final int PSGSIM = 2;
+
+       /** Unknown simulator */
+       public static final int UNKNOWN = -1;
+
+       /** the class names of simulators used */
+       protected static final String[] simName = { "peersim.cdsim.CDSimulator",
+                       "peersim.edsim.EDSimulator", "psgsim.PSGSimulator" };
+
+       /**
+        * Parameter representing the number of times the experiment is run.
+        * Defaults to 1.
+        * 
+        * @config
+        */
+       public static final String PAR_EXPS = "simulation.experiments";
+
+       /**
+        * If present, this parameter activates the redirection of the standard
+        * output to a given PrintStream. This comes useful for processing the
+        * output of the simulation from within the simulator.
+        * 
+        * @config
+        */
+       public static final String PAR_REDIRECT = "simulation.stdout";
+
+       // ==================== static fields ===================================
+       // ======================================================================
+
+       /** */
+       private static int simID = UNKNOWN;
+
+       // ========================== methods ===================================
+       // ======================================================================
+
+       /**
+        * Returns the numeric id of the simulator to invoke. At the moment this can
+        * be {@link #CDSIM}, {@link #EDSIM} or {@link #UNKNOWN}.
+        */
+       public static int getSimID() {
+
+               if (simID == UNKNOWN) {
+                       if (CDSimulator.isConfigurationCycleDriven()) {
+                               simID = CDSIM;
+                       } else if (EDSimulator.isConfigurationEventDriven()) {
+                               simID = EDSIM;
+                       } else
+                               simID = PSGSIM;
+
+               }
+               return simID;
+       }
+
+       // ----------------------------------------------------------------------
+
+       /**
+        * Loads the configuration and executes the experiments. The number of
+        * independent experiments is given by config parameter {@value #PAR_EXPS}.
+        * In all experiments the configuration is the same, only the random seed is
+        * not re-initialized between experiments.
+        * <p>
+        * Loading the configuration is currently done with the help of constructing
+        * an instance of {@link ParsedProperties} using the constructor
+        * {@link ParsedProperties#ParsedProperties(String[])}. The parameter
+        * <code>args</code> is simply passed to this class. This class is then used
+        * to initialize the configuration.
+        * <p>
+        * After loading the configuration, the experiments are run by invoking the
+        * appropriate engine, which is identified as follows:
+        * <ul>
+        * <li>{@link CDSimulator}: if
+        * {@link CDSimulator#isConfigurationCycleDriven} returns true</li>
+        * <li>{@link EDSimulator}: if
+        * {@link EDSimulator#isConfigurationEventDriven} returns true</li>
+        * </ul>
+        * <p>
+        * This list represents the order in which these alternatives are checked.
+        * That is, if more than one return true, then the first will be taken. Note
+        * that this class checks only for these clues and does not check if the
+        * configuration is consistent or valid.
+        * 
+        * @param args
+        *            passed on to
+        *            {@link ParsedProperties#ParsedProperties(String[])}
+        * @throws InterruptedException
+        * @throws HostNotFoundException
+        * @see ParsedProperties
+        * @see Configuration
+        * @see CDSimulator
+        * @see EDSimulator
+        */
+       public static void main(String[] args) throws InterruptedException,
+                       HostNotFoundException {
+               long time = System.currentTimeMillis();
+               long start;
+               System.err.println("Simulator: loading configuration");
+               Configuration.setConfig(new ParsedProperties(args));
+               PrintStream newout = (PrintStream) Configuration.getInstance(
+                               PAR_REDIRECT, System.out);
+               if (newout != System.out)
+                       System.setOut(newout);
+
+               int exps = Configuration.getInt(PAR_EXPS, 1);
+               final int SIMID = getSimID();
+               if (SIMID == UNKNOWN) {
+                       System.err
+                                       .println("Simulator: unable to determine simulation engine type");
+                       return;
+               }
+
+               try {
+
+                       for (int k = 0; k < exps; ++k) {
+                               if (k > 0) {
+                                       long seed = CommonState.r.nextLong();
+                                       CommonState.initializeRandom(seed);
+                               }
+                               System.err.print("Simulator: starting experiment " + k);
+                               System.err.println(" invoking " + simName[SIMID]);
+                               System.err.println("Random seed: "
+                                               + CommonState.r.getLastSeed());
+                               // XXX could be done through reflection, but
+                               // this is easier to read.
+
+                               switch (SIMID) {
+                               case CDSIM:
+                                       CDSimulator.nextExperiment();
+                                       break;
+                               case EDSIM:
+                                       log("ps");
+                                       start = System.currentTimeMillis();
+                                       EDSimulator.nextExperiment();
+                                       System.err.print("Duration of Simulation in ps:"
+                                                       + (System.currentTimeMillis() - start) + " ms\n");
+                                       break;
+                               case PSGSIM:
+                                       try {
+                                               log("psg");
+                                               start = System.currentTimeMillis();
+                                               PSGSimulator.main();
+                                               System.err.print("Duration of Simulation in psg:"
+                                                               + (System.currentTimeMillis() - start)
+                                                               + " ms\n");
+                                       } catch (NativeException e) {
+                                               System.err
+                                                               .println("***********Native exception***************");
+                                               e.printStackTrace();
+                                       }
+                                       break;
+                               }
+                       }
+
+               } catch (MissingParameterException e) {
+                       System.err.println(e + "");
+                       System.exit(1);
+               } catch (IllegalParameterException e) {
+                       System.err.println(e + "");
+                       System.exit(1);
+               }
+
+               // undocumented testing capabilities
+               if (Configuration.contains("__t"))
+                       System.out.println(System.currentTimeMillis() - time);
+               if (Configuration.contains("__x"))
+                       Network.test();
+
+       }
+
+       /**
+        * 
+        * @param sim
+        */
+       public static void log(String sim) {
+               String propName = "OutputName";
+
+               /** le nom de l'OS */
+               final String OS_NAME = System.getProperty("os.name");
+               File file = null;
+               String prot = Configuration.getString(propName, "null");
+               if (prot.contentEquals("null")) {
+                       System.err.println("OutputName parameter not defined");
+               } else {
+                       if ("Linux".equals(OS_NAME) || "Mac".equals(OS_NAME)) {
+                               if (!new File("outputs" + prot).exists()) {
+                                       new File("outputs/" + prot).mkdirs();
+                               }
+                               String path = "outputs/" + prot + "/";
+                               file = new File(path + sim + ".txt");
+                       } else {
+                               if (!new File("outputs" + prot).exists())
+                                       new File("outputs\\" + prot).mkdirs();
+                               String path = "outputs\\" + prot + "\\";
+                               file = new File(path + sim + ".txt");
+                       }
+                       try {
+                               PrintStream printStream = new PrintStream(file);
+                               System.setOut(printStream);
+                               // System.setErr(printStream);
+                       } catch (FileNotFoundException e) {
+                               e.printStackTrace();
+                       }
+               }
+
+       }
+
+}
diff --git a/contrib/psg/src/peersim/cdsim/CDProtocol.java b/contrib/psg/src/peersim/cdsim/CDProtocol.java
new file mode 100644 (file)
index 0000000..c0d2f0d
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.cdsim;
+
+import peersim.core.Protocol;
+import peersim.core.Node;
+
+/**
+* Defines cycle driven protocols, that is, protocols that have a periodic
+* activity in regular time intervals.
+*/
+public interface CDProtocol extends Protocol
+{
+
+/**
+ * A protocol which is defined by performing an algorithm in more or less
+ * regular periodic intervals.
+ * This method is called by the simulator engine once in each cycle with
+ * the appropriate parameters.
+ * 
+ * @param node
+ *          the node on which this component is run
+ * @param protocolID
+ *          the id of this protocol in the protocol array
+ */
+public void nextCycle(Node node, int protocolID);
+
+}
diff --git a/contrib/psg/src/peersim/cdsim/CDSimulator.java b/contrib/psg/src/peersim/cdsim/CDSimulator.java
new file mode 100644 (file)
index 0000000..f487594
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.cdsim;
+
+import java.util.*;
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * This is the cycle driven simulation engine. It is a fully static
+ * singleton class. For a cycle driven simulation the configuration can
+ * describe a set of {@link Protocol}s, and their ordering, a set of
+ * {@link Control}s and their ordering and a set of initializers and their
+ * ordering. See parameters {@value #PAR_INIT}, {@value #PAR_CTRL}. Out
+ * of the set of protocols, this engine only executes the ones that
+ * implement the {@link CDProtocol} interface.
+ * <p>
+ * One experiment run by {@link #nextExperiment} works as follows. First
+ * the initializers are run in the specified order, then the following is
+ * iterated {@value #PAR_CYCLES} times: If {@value #PAR_NOMAIN} is
+ * specified, then simply the controls specified in the configuration are
+ * run in the specified order. If {@value #PAR_NOMAIN} is not specified,
+ * then the controls in the configuration are run in the specified order,
+ * followed by the execution of {@link FullNextCycle}.
+ * <p>
+ * All components (controls and protocols) can have configuration
+ * parameters that control their scheduling (see {@link Scheduler}). This
+ * way they can skip cycles, start from a specified cycle, etc. As a
+ * special case, components can be scheduled to run after the last cycle.
+ * That is, each experiment is finished by running the controls that are
+ * scheduled after the last cycle.
+ * <p>
+ * Finally, any control can interrupt an experiment at any time it is
+ * executed by returning true in method {@link Control#execute}. However,
+ * the controls scheduled to run after the last cycle are still executed
+ * completely, irrespective of their return value and even if the
+ * experiment was interrupted.
+ * @see Configuration
+ */
+public class CDSimulator
+{
+
+// ============== fields ===============================================
+// =====================================================================
+
+/**
+ * Parameter representing the maximum number of cycles to be performed
+ * @config
+ */
+public static final String PAR_CYCLES = "simulation.cycles";
+
+/**
+ * This option is only for experts. It switches off the main cycle that
+ * calls the cycle driven protocols. When you switch this off, you need to
+ * control the execution of the protocols by configuring controls that do
+ * the job (e.g., {@link FullNextCycle}, {@link NextCycle}). It's there for
+ * people who want maximal flexibility for their hacks.
+ * @config
+ */
+private static final String PAR_NOMAIN = "simulation.nodefaultcycle";
+
+/**
+ * This is the prefix for initializers. These have to be of type
+ * {@link Control}. They are run at the beginning of each experiment, in
+ * the order specified by the configuration.
+ * @see Configuration
+ * @config
+ */
+private static final String PAR_INIT = "init";
+
+/**
+ * This is the prefix for controls. These have to be of type
+ * {@link Control}. They are run before each cycle, in the order specified
+ * by the configuration.
+ * @see Configuration
+ * @config
+ */
+private static final String PAR_CTRL = "control";
+
+// --------------------------------------------------------------------
+
+/** The maximum number of cycles to be performed */
+private static int cycles;
+
+/** holds the modifiers of this simulation */
+private static Control[] controls = null;
+
+/** Holds the control schedulers of this simulation */
+private static Scheduler[] ctrlSchedules = null;
+
+// =============== initialization ======================================
+// =====================================================================
+
+/** to prevent construction */
+private CDSimulator()
+{
+}
+
+// =============== private methods =====================================
+// =====================================================================
+
+/**
+ * Load and run initializers.
+ */
+private static void runInitializers()
+{
+
+       Object[] inits = Configuration.getInstanceArray(PAR_INIT);
+       String names[] = Configuration.getNames(PAR_INIT);
+
+       for (int i = 0; i < inits.length; ++i) {
+               System.err.println("- Running initializer " + names[i] + ": "
+                               + inits[i].getClass());
+               ((Control) inits[i]).execute();
+       }
+}
+
+// --------------------------------------------------------------------
+
+private static String[] loadControls()
+{
+
+       boolean nomaincycle = Configuration.contains(PAR_NOMAIN);
+       String[] names = Configuration.getNames(PAR_CTRL);
+       if (nomaincycle) {
+               controls = new Control[names.length];
+               ctrlSchedules = new Scheduler[names.length];
+       } else {
+               // provide for an extra control that handles the main cycle
+               controls = new Control[names.length + 1];
+               ctrlSchedules = new Scheduler[names.length + 1];
+               // calling with a prefix that cannot exist
+               controls[names.length] = new FullNextCycle(" ");
+               ctrlSchedules[names.length] = new Scheduler(" ");
+       }
+       for (int i = 0; i < names.length; ++i) {
+               controls[i] = (Control) Configuration.getInstance(names[i]);
+               ctrlSchedules[i] = new Scheduler(names[i]);
+       }
+       System.err.println("CDSimulator: loaded controls " + Arrays.asList(names));
+       return names;
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * This method is used to check whether the current configuration can be
+ * used for cycle-driven simulations. It checks for the existence of
+ * configuration parameter {@value #PAR_CYCLES}.
+ */
+public static final boolean isConfigurationCycleDriven()
+{
+       return Configuration.contains(PAR_CYCLES);
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * Runs an experiment, resetting everything except the random seed. 
+ */
+public static final void nextExperiment()
+{
+
+       // Reading parameter
+       cycles = Configuration.getInt(PAR_CYCLES);
+       if (CommonState.getEndTime() < 0) // not initialized yet
+               CDState.setEndTime(cycles);
+
+       // initialization
+       CDState.setCycle(0);
+       CDState.setPhase(CDState.PHASE_UNKNOWN);
+       System.err.println("CDSimulator: resetting");
+       controls = null;
+       ctrlSchedules = null;
+       Network.reset();
+       System.err.println("CDSimulator: running initializers");
+       runInitializers();
+
+       // main cycle
+       loadControls();
+
+       System.err.println("CDSimulator: starting simulation");
+       for (int i = 0; i < cycles; ++i) {
+               CDState.setCycle(i);
+
+               boolean stop = false;
+               for (int j = 0; j < controls.length; ++j) {
+                       if (ctrlSchedules[j].active(i))
+                               stop = stop || controls[j].execute();
+               }
+               if (stop)
+                       break;
+               //System.err.println("CDSimulator: cycle " + i + " DONE");
+       }
+
+       CDState.setPhase(CDState.POST_SIMULATION);
+
+       // analysis after the simulation
+       for (int j = 0; j < controls.length; ++j) {
+               if (ctrlSchedules[j].fin)
+                       controls[j].execute();
+       }
+}
+
+}
diff --git a/contrib/psg/src/peersim/cdsim/CDState.java b/contrib/psg/src/peersim/cdsim/CDState.java
new file mode 100644 (file)
index 0000000..ef52f78
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.cdsim;
+
+import peersim.core.CommonState;
+
+
+/**
+ * This is the common state of a cycle driven simulation that all objects see.
+ * It contains additional information, specific to the cycle driven model,
+ * in addition to the info in {@link peersim.core.CommonState}.
+ */
+public class CDState extends CommonState {
+
+
+// ======================= fields ==================================
+// =================================================================
+
+/**
+ * Current time within the current cycle.
+ * Note that {@link #cycle} gives the cycle id to which this value is relative.
+ */
+private static int ctime = -1;
+
+/**
+ * Current cycle in the simulation. It makes sense only in the case of a
+ * cycle based simulator, that is, cycle based simulators will maintain this
+ * value, others will not. It still makes sense to keep it separate from
+ * {@link #time} because it is an int, while time is a long.
+ */
+private static int cycle = -1;
+
+
+// ======================== initialization =========================
+// =================================================================
+
+
+static {}
+
+/** to avoid construction */
+private CDState() {}
+
+// ======================= methods =================================
+// =================================================================
+
+
+/**
+* Returns true if and only if there is a cycle driven simulation going on.
+*/
+public static boolean isCD() { return cycle >= 0; }
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns the current cycle.
+ * Note that {@link #getTime()} returns the same value.
+ * @throws UnsupportedOperationException if no cycle-driven state is available
+ */
+public static int getCycle()
+{
+       if( cycle >= 0 ) return cycle;
+       else throw new UnsupportedOperationException(
+               "Cycle driven state accessed when "+
+               "no cycle state information is available.");
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Sets current cycle. Resets also cycle time to 0. It also calls
+ * {@link #setTime(long)} with the given parameter, to make sure 
+ * {@link #getTime()} is indeed independent of the simulation model.
+ */
+public static void setCycle(int t)
+{
+       cycle = t;
+       ctime = 0;
+       setTime(t);
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns current cycle as an Integer object.
+ * @throws UnsupportedOperationException if no cycle-driven state is available
+ */
+public static Integer getCycleObj()
+{
+       if( cycle >= 0 ) return Integer.valueOf(cycle);
+       else throw new UnsupportedOperationException(
+               "Cycle driven state accessed when "+
+               "no cycle state information is available.");
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns the current time within the current cycle.
+ * Note that the time returned by {@link #getCycle} is the cycle id
+ * in this case. In other words, it returns the number of nodes that have
+ * already been visited in a given cycle.
+ * @throws UnsupportedOperationException if no cycle-driven state is available
+ */
+public static int getCycleT()
+{
+       if( ctime >= 0 ) return ctime;
+       else throw new UnsupportedOperationException(
+               "Cycle driven state accessed when "+
+               "no cycle state information is available.");
+}
+
+// -----------------------------------------------------------------
+
+public static void setCycleT(int t)
+{
+       ctime = t;
+}
+}
+
+
diff --git a/contrib/psg/src/peersim/cdsim/DaemonProtocol.java b/contrib/psg/src/peersim/cdsim/DaemonProtocol.java
new file mode 100644 (file)
index 0000000..73f9a4e
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+package peersim.cdsim;
+
+import java.util.Arrays;
+import peersim.config.Configuration;
+import peersim.core.Node;
+import peersim.core.Control;
+
+/**
+* A protocol that is not really a protocol, but a trick to carry out all
+* kinds of tasks during the simulation. Many users will probably not need it,
+* but it is a nice way to e.g. run controls at any time, not only between cycles.
+*/
+public class DaemonProtocol implements CDProtocol {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+
+/**
+* This is the prefix for network dynamism managers.
+* @config
+*/
+private static final String PAR_CTRL = "control";
+
+/**
+* The controls will be run according to this frequency.
+* It is interpreted within a cycle, in terms of cycle time
+* ({@link CDState#getCycleT}). The first cycletime is 0.
+* Defaults to 1.
+* @config
+*/
+private static final String PAR_STEP = "cstep";
+
+// --------------------------------------------------------------------
+
+private static Control[] controls=null;
+
+private static int step;
+
+// ========================= initialization =========================
+// ==================================================================
+
+
+public DaemonProtocol(String s)
+{  
+       step = Configuration.getInt(s+"."+PAR_STEP,1);
+       
+       String[] names = Configuration.getNames(s+"."+PAR_CTRL);
+       controls = new Control[names.length];
+       for(int i=0; i<names.length; ++i)
+       {
+               controls[i]=(Control)Configuration.getInstance(names[i]);
+       }
+       System.err.println(s+": loaded controls "+Arrays.asList(names));
+}
+
+// ------------------------------------------------------------------
+
+public Object clone() {
+
+       DaemonProtocol ip = null;
+       try { ip=(DaemonProtocol)super.clone(); }
+       catch( CloneNotSupportedException e ) {} // never happens
+       return ip;
+}
+
+
+// ========================= methods =================================
+// ===================================================================
+
+       
+/**
+* Runs the configured controls if {@link CDState#getCycleT} %
+* {@value #PAR_STEP}=0.
+*/
+public void nextCycle( Node node, int protocolID ) {
+
+       if( CDState.getCycleT() % step != 0 ) return;
+       for(int j=0; j<controls.length; ++j) controls[j].execute();
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/cdsim/FullNextCycle.java b/contrib/psg/src/peersim/cdsim/FullNextCycle.java
new file mode 100644 (file)
index 0000000..0bc97f4
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.cdsim;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.RandPermutation;
+
+/**
+* Control to run a cycle of the cycle driven simulation.
+* This does not need to be explicitly configured (although you can do it for
+* hacking purposes).
+*/
+public class FullNextCycle implements Control {
+
+
+// ============== fields ===============================================
+// =====================================================================
+
+
+/**
+* The type of the getPair function. This parameter is of historic interest and
+* was needed in a publication we wrote. You don't need to care about this.
+* But if you wanna know: if set to "rand", then in a cycle the simulator
+* does not simply iterate through the nodes, but instead picks a random one
+* N times, where N is the network size.
+* @config
+*/
+private static final String PAR_GETPAIR = "getpair";
+
+/**
+* Shuffle iteration order if set. Not set by default. If set, then nodes are
+* iterated in a random order. However, in the network the nodes actually
+* stay in the order they originally were. The price for leaving the
+* network untouched is memory: we need to store the permutation we use
+* to iterate the network.
+* @config
+*/
+private static final String PAR_SHUFFLE = "shuffle";
+
+// --------------------------------------------------------------------
+
+protected final boolean getpair_rand;
+
+protected final boolean shuffle;
+
+/** Holds the protocol schedulers of this simulation */
+protected Scheduler[] protSchedules = null;
+
+/** The random permutation to use if config par {@value #PAR_SHUFFLE} is set. */
+protected RandPermutation rperm = new RandPermutation( CDState.r );
+
+// =============== initialization ======================================
+// =====================================================================
+
+/**
+* Reads config parameters and {@link Scheduler}s.
+*/
+public FullNextCycle(String prefix) {
+       
+       getpair_rand = Configuration.contains(prefix+"."+PAR_GETPAIR);
+       shuffle = Configuration.contains(prefix+"."+PAR_SHUFFLE);
+
+       // load protocol schedulers
+       String[] names = Configuration.getNames(Node.PAR_PROT);
+       protSchedules = new Scheduler[names.length];
+       for(int i=0; i<names.length; ++i)
+       {
+               protSchedules[i] = new Scheduler(names[i]);
+       }
+}
+
+// =============== methods =============================================
+// =====================================================================
+
+/** 
+ * Execute all the {@link CDProtocol}s on all nodes that are up.
+ * If the node goes down as a result of the execution of a protocol, then
+ * the rest of the protocols on that node are not executed and we move on
+ * to the next node.
+ * It sets the {@link CDState} appropriately.
+ * @return always false
+ */
+public boolean execute() {
+
+       final int cycle=CDState.getCycle();
+       if( shuffle ) rperm.reset( Network.size() );
+       for(int j=0; j<Network.size(); ++j)
+       {
+               Node node = null;
+               if( getpair_rand )
+                       node = Network.get(CDState.r.nextInt(Network.size()));
+               else if( shuffle )
+                       node = Network.get(rperm.next());
+               else
+                       node = Network.get(j);
+               if( !node.isUp() ) continue; 
+               CDState.setNode(node);
+               CDState.setCycleT(j);
+               final int len = node.protocolSize();
+               for(int k=0; k<len; ++k)
+               {
+                       // Check if the protocol should be executed, given the
+                       // associated scheduler.
+                       if (!protSchedules[k].active(cycle))
+                               continue;
+                               
+                       CDState.setPid(k);
+                       Protocol protocol = node.getProtocol(k);
+                       if( protocol instanceof CDProtocol )
+                       {
+                               ((CDProtocol)protocol).nextCycle(node, k);
+                               if( !node.isUp() ) break;
+                       }
+               }
+       }
+
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/cdsim/NextCycle.java b/contrib/psg/src/peersim/cdsim/NextCycle.java
new file mode 100644 (file)
index 0000000..464f398
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.cdsim;
+
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+* It generalizes its superclass so that the list of protocols to run can
+* be specified. The superclass ({@link FullNextCycle}) always runs all the
+* {@link CDProtocol}s.
+*/
+public class NextCycle extends FullNextCycle {
+
+
+// ============== fields ===============================================
+// =====================================================================
+
+
+/**
+* Gives the list of protocols (whitespace separated) that need to be
+* iterated over.
+* @config
+*/
+private static final String PAR_PROTS = "protocol";
+
+private final int[] pids;
+
+
+// =============== initialization ======================================
+// =====================================================================
+
+/**
+* reads configuration parameters and the {@link Scheduler}s.
+*/
+public NextCycle(String prefix) {
+       
+       super(prefix);
+       
+       String prots = Configuration.getString(prefix+"."+PAR_PROTS);
+       String[] protnames = prots.split("\\s");
+       pids = new int[protnames.length];
+       for(int i=0; i<protnames.length; ++i)
+       {
+               pids[i] = Configuration.lookupPid(protnames[i]);
+       }
+}
+
+// =============== methods =============================================
+// =====================================================================
+
+/** 
+ * Execute the configured protocols on all nodes.
+ * It works exactly as {@link FullNextCycle#execute}, only just the configured
+ * protocols are iterated over.
+ */
+public boolean execute() {
+
+       final int cycle=CDState.getCycle();
+       if( shuffle ) rperm.reset( Network.size() );
+       for(int j=0; j<Network.size(); ++j)
+       {
+               Node node = null;
+               if( getpair_rand )
+                       node = Network.get(CDState.r.nextInt(Network.size()));
+               else if( shuffle )
+                       node = Network.get(rperm.next());
+               else
+                       node = Network.get(j);
+               if( !node.isUp() ) continue; 
+               CDState.setNode(node);
+               CDState.setCycleT(j);
+               for(int pid: pids)
+               {
+                       // Check if the protocol should be executed, given the
+                       // associated scheduler.
+                       if (!protSchedules[pid].active(cycle))
+                               continue;
+                               
+                       CDState.setPid(pid);
+                       Protocol protocol = node.getProtocol(pid);
+                       if( protocol instanceof CDProtocol )
+                       {
+                               ((CDProtocol)protocol).nextCycle(node, pid);
+                               if( !node.isUp() ) break;
+                       }
+               }
+       }
+
+       return false;
+}
+
+}
+
+
diff --git a/contrib/psg/src/peersim/cdsim/Shuffle.java b/contrib/psg/src/peersim/cdsim/Shuffle.java
new file mode 100644 (file)
index 0000000..6373940
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.cdsim;
+
+import peersim.core.*;
+
+/**
+* Shuffles the network. After shuffling, the order in which the nodes
+* are iterated over during a cycle of a cycle driven simulation
+* will be random. It has an effect only in cycle driven simulations.
+*/
+public class Shuffle implements Control {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+// ==================== initialization ==============================
+// ==================================================================
+
+/** Does nothing. */
+public Shuffle(String prefix) {}
+
+
+// ===================== public methods ==============================
+// ===================================================================
+
+
+/**
+* Calls {@link Network#shuffle()}. 
+* As a result, the order in which the nodes
+* are iterated over during a cycle of a cycle driven simulation
+* will be random. It has an effect only in cycle driven simulations.
+*/
+public final boolean execute() {
+       Network.shuffle();
+       return false;
+}
+
+
+}
+
+
diff --git a/contrib/psg/src/peersim/config/CheckConfig.java b/contrib/psg/src/peersim/config/CheckConfig.java
new file mode 100644 (file)
index 0000000..117dcc0
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+import java.util.*;
+
+import peersim.cdsim.*;
+import peersim.edsim.*;
+import peersim.util.*;
+
+
+/**
+ * This is utility tool that checks whether a config file can be loaded
+ * or not, without actually performing the simulation. All the error
+ * messages generated by controls and protocols when initialized are
+ * reported.  This is useful to check all the configuration files in a 
+ * directory.
+ */
+public class CheckConfig {
+
+//========================== parameters ================================
+//======================================================================
+
+/**
+ * This is the prefix of the config properties whose value vary during
+ * a set of experiments.
+ * @config
+ */
+private static final String PAR_RANGE = "range";
+
+
+// ========================== static constants ==========================
+// ======================================================================
+
+/** {@link CDSimulator} */
+protected static final int CDSIM = 0;
+
+/** {@link EDSimulator} */
+protected static final int EDSIM = 1;
+
+protected static final int UNKNOWN = -1;
+
+/** the class names of simulators used */
+protected static final String[] simName = {
+       CDSimulator.class.getCanonicalName(),
+       EDSimulator.class.getCanonicalName(),
+};
+
+
+
+       
+// ========================== methods ===================================
+// ======================================================================
+
+/**
+* Returns the numeric id of the simulator to invoke. At the moment this can
+* be {@link #CDSIM}, {@link #EDSIM} or {@link #UNKNOWN}.
+*/
+protected static int getSimID() {
+       
+       if( CDSimulator.isConfigurationCycleDriven())
+       {
+               return CDSIM;
+       }
+       else if( EDSimulator.isConfigurationEventDriven() )
+       {       
+               return EDSIM;
+       }
+       else    return UNKNOWN;
+}
+
+// ----------------------------------------------------------------------
+
+/**
+* Loads the configuration and checks the configuration files against
+* simple configuration errors, such as missing classes, missing 
+* parameters or syntax errors.
+* <p>
+* The goal is to provide a mechanism to test a configuration file,
+* without having to perform the actual simulations (that could be
+* time-consuming) and without necessarily blocking after the first
+* error encountered. It may be useful, for example, when a major 
+* refactoring of your code requires a thorough check on all your 
+* configuration files.
+* <p>
+* Loading the configuration is currently done with the help of 
+* constructing an instance of {@link ParsedProperties} using the 
+* constructor {@link ParsedProperties#ParsedProperties(String[])},
+* in the same way as the normal simulator.
+* <p>
+* After loading the configuration, the collection of nodes forming a 
+* Network is instantiated, together with all protocols forming a
+* node. Initialization controls are executed, and then the simulation
+* stops. 
+* <p>
+* For each error encountered, a message is printed ons standard error,
+* and the initialization keeps going without interruption. If multiple 
+* errors are present, an error message for each of them is printed.
+* Apart from errors, default choices are also printed as warnings, to 
+* allow developers to spot subtle configuration errors such as missing
+* parameters that defaults to standard values.
+* 
+* @param args passed on to
+* {@link ParsedProperties#ParsedProperties(String[])}
+*/
+public static void main(String[] args)
+  throws Exception
+{
+       System.setErr(new NullPrintStream());
+       Properties prop = new ParsedProperties(args);
+       Configuration.setConfig( prop, true );
+       parseRanges(prop);
+       
+       final int SIMID = getSimID();
+       if( SIMID == UNKNOWN )
+       {
+               System.err.println(
+                   "Simulator: unable to identify configuration, exiting.");
+               return;
+       }
+       
+       try {
+       
+               // XXX could be done through reflection, but
+               // this is easier to read.
+               switch(SIMID)
+               {
+               case CDSIM:
+                       // Set cycles to 0, so no simulation is ever performed.
+                       prop.setProperty(CDSimulator.PAR_CYCLES, "0");
+                       CDSimulator.nextExperiment();
+                       break;
+               case EDSIM:
+                       // Set endtime to 0, so no simulation is ever performed.
+                       prop.setProperty(EDSimulator.PAR_ENDTIME, "0");
+                       EDSimulator.nextExperiment();
+                       break;
+               }
+       
+       } catch (MissingParameterException e) {
+               System.out.println(e.getMessage());
+               System.exit(1);
+       } catch (IllegalParameterException e) {
+               System.out.println(e.getMessage());
+               System.exit(1);
+       }       
+}
+
+/**
+ * Parses a collection of range specifications, identifies the set
+ * of parameters that will change during the simulation and
+ * instantiates them with the first value of their ranges.
+ */
+private static void parseRanges(Properties prop)
+{
+       // Get ranges
+       String[] ranges = Configuration.getNames(PAR_RANGE);
+
+       for (int i = 0; i < ranges.length; i++) {
+               String[] array = Configuration.getString(ranges[i]).split(";");
+               if (array.length != 2) {
+                       throw new IllegalParameterException(ranges[i],
+                                       " should be formatted as <parameter>;<value list>");
+               }
+               String[] values = StringListParser.parseList(array[1]);
+               prop.setProperty(array[0], values[0]);
+       }
+}
+
+}
diff --git a/contrib/psg/src/peersim/config/ClassFinder.java b/contrib/psg/src/peersim/config/ClassFinder.java
new file mode 100644 (file)
index 0000000..b7cab6b
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+/**
+ * Provides static methods to obtain the package-qualified class name
+ * of a class, given just the non-qualified name, and to obtain
+ * the non-qualified name, given the package-qualified class name.
+ * 
+ * Inspired from some code written by David Postill (david@postill.org.uk)
+ * (found in http://groups.google.com).
+ *
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.9 $
+ */
+class ClassFinder 
+{
+
+//--------------------------------------------------------------------------
+//Fields and initialization
+//--------------------------------------------------------------------------
+       
+       
+/** Local map containing the associations */
+private static Map<String,String> map = new TreeMap<String,String>();  
+
+/** The number of directories that have been touched by the search.
+This does not include directories in jar files. */
+private static int visitedDirs = 0;
+
+private static final int maxDirs;
+
+static {
+
+       maxDirs = 10000;
+
+       try {
+               findClasses(map);
+       } catch (IOException e) {
+               e.printStackTrace();
+       }
+
+       if(visitedDirs >= maxDirs )
+       {
+               System.err.println("Configuration: some directories in your "+
+               "classpath probably contain filesystem\nConfiguration: "+
+               "loops because the number of visited directories "+
+               "reached "+maxDirs+".\nConfiguration: This means automatic "+
+               "class lookup might fail and you might have\nConfiguration: "+
+               "to fully qualify class names in the configuration.");
+       }
+}
+       
+       
+//--------------------------------------------------------------------------
+//Public static methods
+//--------------------------------------------------------------------------
+       
+/**
+ * Returns the non-qualified name of a class, removing all the package
+ * information.
+ */
+public static String getShortName(String className) {
+
+       int index = className.lastIndexOf('.');
+       if (index < 0) {
+               return className;
+       } else {
+               return className.substring(index+1);
+       }
+}
+
+/**
+ * Returns the package-qualified name associated to the specified
+ * non-qualified name, if exists. Otherwise it returns null.
+ * 
+ * Only classes reachable from the classpath defined by the 
+ * "java.class.path" property are considered. 
+ * Jar files and directories are both parsed.
+ * If multiple classes with the same name but different 
+ * fully-qualified names are present, a comma-separated list
+ * of fully-qualified class names is returned.
+ * 
+ * @param name the non-qualified name of the class to be searched
+ * @return the qualified name, if exists.
+ */
+public static String getQualifiedName(String name)
+{
+       return map.get(name);
+}
+
+//--------------------------------------------------------------------------
+//Private static methods
+//--------------------------------------------------------------------------
+       
+/**
+ * Finds all the classes reachable from the current classpath;
+ * for each of them, inserts an association (name, fully-qualified 
+ * name) in the specified map. Both names are String objects.
+ * 
+ * Only classes reachable from the classpath defined by the 
+ * "java.class.path" property are considered. 
+ * Jar files and directories are both parsed.
+ * If multiple classes with the same name but different 
+ * fully-qualified names are present, they are inserted
+ * in the map as associations (name, comma-separated list of
+ * fully-qualified names).
+ * 
+ * @param map
+ * @throws IOException
+ */
+private static void findClasses(Map<String,String> map)
+throws IOException
+{
+       String classPath = System.getProperty( "java.class.path" );
+       String separator = System.getProperty( "path.separator"  );
+       String filesep = System.getProperty( "file.separator");
+       StringTokenizer path = new StringTokenizer( classPath, separator );
+
+       while( path.hasMoreTokens() ) {
+               
+               String pathElement = path.nextToken();
+               File pathFile = new File( pathElement );
+               
+               if( pathFile.isDirectory() ) {
+                       if (!pathElement.endsWith(filesep)) {
+                               pathElement = pathElement + filesep;
+                               pathFile = new File( pathElement);
+                       }
+                       findClassInPathDir( map, pathElement, pathFile );
+                       // Search directories
+               } else if ( pathFile.exists() ) {
+                       findClassInJar( map, pathFile);
+               }
+       }
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Parses jar file.
+ * 
+ * @param map the map where to insert associations
+ * @param pathFile the file name of the associated jar file
+ * @throws IOException
+ */
+private static void findClassInJar(Map<String,String> map, File pathFile)
+throws IOException
+{
+       ZipFile zipFile = new ZipFile( pathFile );
+       Enumeration entries = zipFile.entries();
+       while( entries.hasMoreElements() ) {
+               
+               String entry = entries.nextElement().toString();
+               if( entry.endsWith( ".class" ) ) {
+                       // File names in ZIP archives (so, also in JARs)
+                       // are separated by forward slashes '/', independently
+                       // of the architecture.
+                       String className = classname( entry, "/" ); 
+                       String shortName = getShortName( className );
+                       if (map.containsKey(shortName)) {
+                               map.put(shortName,
+                                       map.get(shortName)+","+className);
+                       } else {
+                               map.put(shortName, className);
+                       }
+               }
+       }
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Recursively parses directories.
+ * 
+ * @param map the map where to insert associations
+ * @param pathElement the path string used for recursion
+ * @param pathFile the file (directory) to be analyzed
+ * @throws IOException
+ */
+private static void findClassInPathDir( Map<String,String> map,
+       String pathElement, File pathFile )
+throws IOException
+{
+       visitedDirs++;
+       if(visitedDirs>=maxDirs) return;
+
+       String[] list = pathFile.list();
+       String filesep = System.getProperty( "file.separator");
+       
+       for( int i = 0; i < list.length; i++ ) {
+               File file = new File( pathFile, list[i] );
+               if( file.isDirectory() ) {
+                       findClassInPathDir( map, pathElement, file );
+               }
+               else if ( file.exists() && (file.length() != 0) && list[i].endsWith( ".class" ) ) {
+                       String classFile = file.toString().substring( pathElement.length());
+                       String className = classname( classFile, filesep );
+                       String shortName = getShortName( className );
+                       if (map.containsKey(shortName)) {
+                               map.put(shortName, map.get(shortName)+","+className);
+                       } else {
+                               map.put(shortName, className);
+                       }
+               }
+       }
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Translates a class file name in a class name using
+ * the specified file separator.
+ */
+private static String classname(String classFile, String filesep)
+{ 
+       return classFile.replace( filesep, "." ).substring(
+               0, classFile.length() - ".class".length() ); 
+}
+
+//--------------------------------------------------------------------------
+
+/** 
+ * Testing.
+ * 
+ * @param argv
+ */
+public static void main( String[] argv )
+{
+       Iterator i = map.keySet().iterator();
+       while (i.hasNext()) {
+               String key = (String) i.next();
+               String name = map.get(key);
+               System.out.println(key + " --> " + name);
+       }
+}
+}
diff --git a/contrib/psg/src/peersim/config/ConfigContainer.java b/contrib/psg/src/peersim/config/ConfigContainer.java
new file mode 100644 (file)
index 0000000..75f3cb6
--- /dev/null
@@ -0,0 +1,1011 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+import java.lang.reflect.*;
+import java.util.*;
+import org.lsmp.djep.groupJep.*;
+
+/**
+ * This class is the container for the configuration data used in
+ * {@link Configuration}; see that class for more information.
+ */
+public class ConfigContainer
+{
+
+// =================== static fields =================================
+// ===================================================================
+
+/** Symbolic constant for no debug */
+private static final int DEBUG_NO = 0;
+
+/** Symbolic constant for regular debug */
+private static final int DEBUG_REG = 1;
+
+/** Symbolic constant for extended debug */
+private static final int DEBUG_CONTEXT = 2;
+
+//========================== fields =================================
+//===================================================================
+
+/**
+ * The properties object that stores all configuration information.
+ */
+private Properties config;
+
+/**
+ * Map associating string protocol names to the numeric protocol
+ * identifiers. The protocol names are understood without prefix.
+ */
+private Map<String, Integer> protocols;
+
+/**
+ * The maximum depth that can be reached when analyzing expressions. This
+ * value can be substituted by setting the configuration parameter
+ * PAR_MAXDEPTH.
+ */
+private int maxdepth;
+
+/** Debug level */
+private int debugLevel;
+
+/**
+ * If true, no exception is thrown. Instead, an error is printed and the
+ * Configuration tries to return a reasonable return value
+ */
+private boolean check = false;
+
+// =================== initialization ================================
+// ===================================================================
+
+public ConfigContainer(Properties config, boolean check)
+{
+       this.config = config;
+       this.check = check;
+       maxdepth = getInt(Configuration.PAR_MAXDEPTH, Configuration.DEFAULT_MAXDEPTH);
+
+       // initialize protocol id-s
+       protocols = new HashMap<String, Integer>();
+       String[] prots = getNames(Configuration.PAR_PROT);// they're returned in correct order
+       for (int i = 0; i < prots.length; ++i) {
+               protocols.put(prots[i].substring(Configuration.PAR_PROT.length() + 1), Integer.valueOf(i));
+       }
+       String debug = config.getProperty(Configuration.PAR_DEBUG);
+       if (Configuration.DEBUG_EXTENDED.equals(debug))
+               debugLevel = DEBUG_CONTEXT;
+       else if (Configuration.DEBUG_FULL.equals(debug)) {
+               Map<String, String> map = new TreeMap<String, String>();
+               Enumeration e = config.propertyNames();
+               while (e.hasMoreElements()) {
+                       String name = (String) e.nextElement();
+                       String value = config.getProperty(name);
+                       map.put(name, value);
+               }
+               Iterator i = map.keySet().iterator();
+               while (i.hasNext()) {
+                       String name = (String) i.next();
+                       System.err.println("DEBUG " + name
+                                       + ("".equals(map.get(name)) ? "" : " = " + map.get(name)));
+               }
+       } else if (debug != null) {
+               debugLevel = DEBUG_REG;
+       } else {
+               debugLevel = DEBUG_NO;
+       }
+}
+
+// =================== static public methods =========================
+// ===================================================================
+
+/**
+ * @return true if and only if name is a specified (existing) property.
+ */
+public boolean contains(String name)
+{
+       boolean ret = config.containsKey(name);
+       debug(name, "" + ret);
+       return ret;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public boolean getBoolean(String name, boolean def)
+{
+       try {
+               return getBool(name);
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return def;
+       }
+}
+
+// -------------------------------------------------------------------
+
+
+/**
+ * Reads given property. If not found, or the value is empty string then
+ * throws a {@link MissingParameterException}. Empty string is not
+ * accepted as false due to the similar function of {@link #contains} which
+ * returns true in that case. True is returned if the lowercase value of
+ * the property is "true", otherwise false is returned.
+ * @param name
+ *          Name of configuration property
+ */
+public boolean getBoolean(String name)
+{
+       try {
+               return getBool(name);
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return false;
+       }
+}
+
+//-------------------------------------------------------------------
+
+/**
+ * The actual methods that implements getBoolean.
+ */
+private boolean getBool(String name)
+{
+       if (config.getProperty(name) == null) {
+               throw new MissingParameterException(name);
+//                             "\nPossibly incorrect property: " + getSimilarProperty(name));
+       }
+       if (config.getProperty(name).matches("\\p{Blank}*")) {
+               throw new MissingParameterException(name,
+                               "Blank value is not accepted when parsing Boolean.");
+       }
+       boolean ret = Boolean.valueOf(config.getProperty(name));
+       debug(name, "" + ret);
+       return ret;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public int getInt(String name, int def)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.intValue();
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return def;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ *          Name of configuration property
+ */
+public int getInt(String name)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.intValue();
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return 0;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public long getLong(String name, long def)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.longValue();
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return def;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ *          Name of configuration property
+ */
+public long getLong(String name)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.longValue();
+       } catch (RuntimeException e) {
+               manageException(name, e);
+                       return 0;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public double getDouble(String name, double def)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.doubleValue();
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return def;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * MissingParameterException.
+ * @param name
+ *          Name of configuration property
+ */
+public double getDouble(String name)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.doubleValue();
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return 0;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Read numeric property values, parsing expression if necessary.
+ * 
+ * @param initial
+ *          the property name that started this expression evaluation
+ * @param property
+ *          the current property name to be evaluated
+ * @param depth
+ *          the depth reached so far
+ * @return the evaluation of the expression associated to property
+ */
+private Number getVal(String initial, String property, int depth)
+{
+       if (depth > maxdepth) {
+               throw new IllegalParameterException(initial,
+                               "Probable recursive definition - exceeded maximum depth " + 
+                               maxdepth);
+       }
+
+       String s = config.getProperty(property);
+       if (s == null || s.equals("")) {
+               throw new MissingParameterException(property,
+                               " when evaluating property " + initial);
+//                                             + "\nPossibly incorrect property: " + getSimilarProperty(property));
+       }
+
+       GroupJep jep = new GroupJep(new Operators());
+       jep.setAllowUndeclared(true);
+
+       jep.parseExpression(s);
+       String[] symbols = getSymbols(jep);
+       for (int i = 0; i < symbols.length; i++) {
+               Object d = getVal(initial, symbols[i], depth + 1);
+               jep.addVariable(symbols[i], d);
+       }
+       Object ret = jep.getValueAsObject();
+       if (jep.hasError())
+               System.err.println(jep.getErrorInfo());
+       return (Number) ret;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns an array of string, containing the symbols contained in the
+ * expression parsed by the specified JEP parser.
+ * @param jep
+ *          the java expression parser containing the list of variables
+ * @return an array of strings.
+ */
+private String[] getSymbols(org.nfunk.jep.JEP jep)
+{
+       Hashtable h = jep.getSymbolTable();
+       String[] ret = new String[h.size()];
+       Enumeration e = h.keys();
+       int i = 0;
+       while (e.hasMoreElements()) {
+               ret[i++] = (String) e.nextElement();
+       }
+       return ret;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public String getString(String name, String def)
+{
+       try {
+               return getStr(name);
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return def;
+       } 
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * MissingParameterException. Removes trailing whitespace characters.
+ * @param name
+ *          Name of configuration property
+ */
+public String getString(String name)
+{
+       try {
+               return getStr(name);
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return "";
+       }
+}
+
+/**
+ * The actual method implementing getString().
+ */
+private String getStr(String name)
+{
+       String result = config.getProperty(name);
+       if (result == null) {
+               throw new MissingParameterException(name);
+//                             "\nPossibly incorrect property: " + getSimilarProperty(name));
+       }
+       debug(name, "" + result);
+
+       return result.trim();
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads the given property from the configuration interpreting it as a
+ * protocol name. Returns the numeric protocol identifier of this protocol
+ * name. See the discussion of protocol name at {@link Configuration} for
+ * details on how this numeric id is calculated
+ * 
+ * @param name
+ *          Name of configuration property
+ * @return the numeric protocol identifier associated to the value of the
+ *         property
+ */
+public int getPid(String name)
+{
+       try {
+               String protname = getStr(name);
+               return lookupPid(protname);
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return 0;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Calls {@link #getPid(String)}, and returns the default if no property
+ * is defined with the given name.
+ * 
+ * @param name
+ *          Name of configuration property
+ * @param pid
+ *          the default protocol identifier
+ * @return the numeric protocol identifier associated to the value of the
+ *         property, or the default if not defined
+ */
+public int getPid(String name, int pid)
+{
+       try {
+               String protname = getStr(name);
+               return lookupPid(protname);
+       } catch (RuntimeException e) {
+               manageDefault(name, pid, e);
+               return pid;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns the numeric protocol identifier of the given protocol name.
+ * 
+ * @param protname
+ *          the protocol name.
+ * @return the numeric protocol identifier associated to the protocol name
+ */
+public int lookupPid(String protname)
+{
+       Integer ret = protocols.get(protname);
+       if (ret == null) {
+               throw new MissingParameterException(Configuration.PAR_PROT + "." + protname);
+//                             "\nPossibly incorrect property: "
+//                             + getSimilarProperty(PAR_PROT + "." + protname));
+       }
+       return ret.intValue();
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns the name of a protocol that has the given identifier.
+ * <p>
+ * Note that this is not a constant time operation in the number of
+ * protocols, although typically there are very few protocols defined.
+ * 
+ * @param pid
+ *          numeric protocol identifier.
+ * @return name of the protocol that has the given id. null if no protocols
+ *         have the given id.
+ */
+public String lookupPid(int pid)
+{
+
+       if (!protocols.containsValue(pid))
+               return null;
+       for (Map.Entry<String, Integer> i : protocols.entrySet()) {
+               if (i.getValue().intValue() == pid)
+                       return i.getKey();
+       }
+
+       // never reached but java needs it...
+       return null;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}. When creating the Class object, a
+ * few attempts are done to resolve the classname. See
+ * {@link Configuration} for details.
+ * @param name
+ *          Name of configuration property
+ */
+public Class getClass(String name)
+{
+       try {
+               return getClazz(name);
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return null;
+       }
+}
+
+private Class getClazz(String name)
+{
+       String classname = config.getProperty(name);
+       if (classname == null) {
+               throw new MissingParameterException(name);
+//                             "\nPossibly incorrect property: " + getSimilarProperty(name));
+       }
+       debug(name, classname);
+
+       Class c = null;
+
+       try {
+               // Maybe classname is just a fully-qualified name
+               c = Class.forName(classname);
+       } catch (ClassNotFoundException e) {
+       }
+       if (c == null) {
+               // Maybe classname is a non-qualified name?
+               String fullname = ClassFinder.getQualifiedName(classname);
+               if (fullname != null) {
+                       try {
+                               c = Class.forName(fullname);
+                       } catch (ClassNotFoundException e) {
+                       }
+               }
+       }
+       if (c == null) {
+               // Maybe there are multiple classes with the same
+               // non-qualified name.
+               String fullname = ClassFinder.getQualifiedName(classname);
+               if (fullname != null) {
+                       String[] names = fullname.split(",");
+                       if (names.length > 1) {
+                               for (int i = 0; i < names.length; i++) {
+                                       for (int j = i + 1; j < names.length; j++) {
+                                               if (names[i].equals(names[j])) {
+                                                       throw new IllegalParameterException(name,
+                                                                       "The class " + names[i]
+                                                               + " appears more than once in the classpath; please check"
+                                                               + " your classpath to avoid duplications.");
+                                               }
+                                       }
+                               }
+                               throw new IllegalParameterException(name,
+                                               "The non-qualified class name " + classname
+                                                               + "corresponds to multiple fully-qualified classes:" + fullname);
+                       }
+               }
+       }
+       if (c == null) {
+               // Last attempt: maybe the fully classified name is wrong,
+               // but the classname is correct.
+               String shortname = ClassFinder.getShortName(classname);
+               String fullname = ClassFinder.getQualifiedName(shortname);
+               if (fullname != null) {
+                       throw new IllegalParameterException(name, "Class "
+                                       + classname + " does not exist. Possible candidate(s): " + fullname);
+               }
+       }
+       if (c == null) {
+               throw new IllegalParameterException(name, "Class "
+                               + classname + " not found");
+       }
+       return c;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ * @see #getClass(String)
+ */
+public Class getClass(String name, Class def)
+{
+
+       try {
+               return Configuration.getClass(name);
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return def;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property for a class name. It returns an
+ * instance of the class. The class must implement a constructor that takes
+ * a String as an argument. The value of this string will be <tt>name</tt>.
+ * The constructor of the class can see the configuration so it can make
+ * use of this name to read its own parameters from it.
+ * @param name
+ *          Name of configuration property
+ * @throws MissingParameterException
+ *           if the given property is not defined
+ * @throws IllegalParameterException
+ *           if there is any problem creating the instance
+ */
+public Object getInstance(String name)
+{
+  try {
+       return getInst(name);
+  } catch (RuntimeException e) {
+               manageException(name, e);
+               return null;
+  }
+}
+
+/**
+ * The actual method implementing getInstance().
+ */
+private Object getInst(String name)
+{
+       Class c = getClass(name);
+       if (c == null)
+               return null;
+       final String classname = c.getSimpleName();
+
+       try {
+               Class pars[] = {String.class};
+               Constructor cons = c.getConstructor(pars);
+               Object objpars[] = {name};
+               return cons.newInstance(objpars);
+       } catch (NoSuchMethodException e) {
+               throw new IllegalParameterException(name, "Class "
+                               + classname + " has no " + classname + "(String) constructor");
+       } catch (InvocationTargetException e) {
+               if (e.getTargetException() instanceof RuntimeException) {
+                       throw (RuntimeException) e.getTargetException();
+               } else {
+                       e.getTargetException().printStackTrace();
+                       throw new RuntimeException("" + e.getTargetException());
+               }
+       } catch (Exception e) {
+               throw new IllegalParameterException(name, e + "");
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property for a class name. It returns an
+ * instance of the class. The class must implement a constructor that takes
+ * a String as an argument. The value of this string will be <tt>name</tt>.
+ * The constructor of the class can see the configuration so it can make
+ * use of this name to read its own parameters from it.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          The default object that is returned if there is no property
+ *          defined with the given name
+ * @throws IllegalParameterException
+ *           if the given name is defined but there is a problem creating
+ *           the instance.
+ */
+public Object getInstance(String name, Object def)
+{
+  if (!contains(name)) 
+       return def;
+       try {
+               return getInst(name);
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return def;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * It returns an array of class instances. The instances are constructed by
+ * calling {@link #getInstance(String)} on the names returned by
+ * {@link #getNames(String)}.
+ * @param name
+ *          The component type (i.e. prefix of the list of configuration
+ *          properties) which will be passed to {@link #getNames(String)}.
+ */
+public Object[] getInstanceArray(String name)
+{
+
+       String names[] = getNames(name);
+       Object[] result = new Object[names.length];
+
+       for (int i = 0; i < names.length; ++i) {
+               result[i] = getInstance(names[i]);
+       }
+
+       return result;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns an array of names prefixed by the specified name. The array is
+ * sorted as follows. If there is no config entry
+ * <code>{@value peersim.config.Configuration#PAR_INCLUDE}+"."+name</code> or
+ * <code>{@value peersim.config.Configuration#PAR_ORDER}+"."+name</code> then the order is
+ * alphabetical. Otherwise this entry defines the order. For more
+ * information see {@link Configuration}.
+ * @param name
+ *          the component type (i.e., the prefix)
+ * @return the full property names in the order specified by the
+ *         configuration
+ */
+public String[] getNames(String name)
+{
+       ArrayList<String> ll = new ArrayList<String>();
+       final String pref = name + ".";
+
+       Enumeration e = config.propertyNames();
+       while (e.hasMoreElements()) {
+               String key = (String) e.nextElement();
+               if (key.startsWith(pref) && key.indexOf(".", pref.length()) < 0)
+                       ll.add(key);
+       }
+       String[] ret = ll.toArray(new String[ll.size()]);
+       return order(ret, name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * The input of this method is a set of property <code>names</code> (e.g.
+ * initializers, controls and protocols) and a string specifying the type
+ * (prefix) of these. The output is in <code>names</code>, which will
+ * contain a permutation of the original array. Parameter
+ * PAR_INCLUDE+"."+type, or if not present, PAR_ORDER+"."+type is read from
+ * the configuration. If none of them are defined then the order is
+ * identical to that of <code>names</code>. Otherwise the configuration
+ * entry must contain entries from <code>names</code>. It is assumed
+ * that the entries in <code>names</code> contain only word characters
+ * (alphanumeric and underscore '_'. The order configuration entry thus
+ * contains a list of entries from <code>names</code> separated by any
+ * non-word characters.
+ * <p>
+ * It is not required that all entries are listed. If PAR_INCLUDE is used,
+ * then only those entries are returned that are listed. If PAR_ORDER is
+ * used, then all names are returned, but the array will start with those
+ * that are listed. The rest of the names follow in alphabetical order.
+ * 
+ * 
+ * @param names
+ *          the set of property names to be searched
+ * @param type
+ *          the string identifying the particular set of properties to be
+ *          inspected
+ */
+private String[] order(String[] names, String type)
+{
+       String order = getString(Configuration.PAR_INCLUDE + "." + type, null);
+       boolean include = order != null;
+       if (!include)
+               order = getString(Configuration.PAR_ORDER + "." + type, null);
+
+       int i = 0;
+       if (order != null && !order.equals("")) {
+               // split around non-word characters
+               String[] sret = order.split("\\W+");
+               for (; i < sret.length; i++) {
+                       int j = i;
+                       for (; j < names.length; ++j)
+                               if (names[j].equals(type + "." + sret[i]))
+                                       break;
+                       if (j == names.length) {
+                               throw new IllegalParameterException(
+                                               (include ? Configuration.PAR_INCLUDE : Configuration.PAR_ORDER)
+                                               + "." + type, type + "." + sret[i] + " is not defined.");
+                       } else // swap the element to current position
+                       {
+                               String tmps = names[j];
+                               names[j] = names[i];
+                               names[i] = tmps;
+                       }
+               }
+       }
+
+       Arrays.sort(names, i, names.length);
+       int retsize = (include ? i : names.length);
+       String[] ret = new String[retsize];
+       for (int j = 0; j < retsize; ++j)
+               ret[j] = names[j];
+       return ret;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Print debug information for configuration. The amount of information
+ * depends on the debug level DEBUG. 0 = nothing 1 = just the config name 2 =
+ * config name plus method calling
+ * 
+ * @param name
+ */
+private void debug(String name, String result)
+{
+       if (debugLevel == DEBUG_NO)
+               return;
+       StringBuffer buffer = new StringBuffer();
+       buffer.append("DEBUG ");
+       buffer.append(name);
+       buffer.append(" = ");
+       buffer.append(result);
+
+       // Additional info
+       if (debugLevel == DEBUG_CONTEXT) {
+
+               buffer.append("\n  at ");
+               // Obtain the stack trace
+               StackTraceElement[] stack = null;
+               try {
+                       throw new Exception();
+               } catch (Exception e) {
+                       stack = e.getStackTrace();
+               }
+
+               // Search the element that invoked Configuration
+               // It's the first whose class is different from Configuration
+               int pos;
+               for (pos = 0; pos < stack.length; pos++) {
+                       if (!stack[pos].getClassName().equals(Configuration.class.getName()))
+                               break;
+               }
+
+               buffer.append(stack[pos].getClassName());
+               buffer.append(":");
+               buffer.append(stack[pos].getLineNumber());
+               buffer.append(", method ");
+               buffer.append(stack[pos - 1].getMethodName());
+               buffer.append("()");
+       }
+
+       System.err.println(buffer);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * @return an array of adjacent letter pairs contained in the input string
+ *         http://www.catalysoft.com/articles/StrikeAMatch.html
+ */
+private String[] letterPairs(String str)
+{
+       int numPairs = str.length() - 1;
+       String[] pairs = new String[numPairs];
+       for (int i = 0; i < numPairs; i++) {
+               pairs[i] = str.substring(i, i + 2);
+       }
+       return pairs;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * @return an ArrayList of 2-character Strings.
+ *         http://www.catalysoft.com/articles/StrikeAMatch.html
+ */
+private ArrayList<String> wordLetterPairs(String str)
+{
+       ArrayList<String> allPairs = new ArrayList<String>();
+       // Tokenize the string and put the tokens/words into an array
+       String[] words = str.split("\\s");
+       // For each word
+       for (int w = 0; w < words.length; w++) {
+               // Find the pairs of characters
+               String[] pairsInWord = letterPairs(words[w]);
+               for (int p = 0; p < pairsInWord.length; p++) {
+                       allPairs.add(pairsInWord[p]);
+               }
+       }
+       return allPairs;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * @return lexical similarity value in the range [0,1]
+ *         http://www.catalysoft.com/articles/StrikeAMatch.html
+ */
+private double compareStrings(String str1, String str2)
+{
+       ArrayList pairs1 = wordLetterPairs(str1.toUpperCase());
+       ArrayList pairs2 = wordLetterPairs(str2.toUpperCase());
+       int intersection = 0;
+       int union_ = pairs1.size() + pairs2.size();
+       for (int i = 0; i < pairs1.size(); i++) {
+               Object pair1 = pairs1.get(i);
+               for (int j = 0; j < pairs2.size(); j++) {
+                       Object pair2 = pairs2.get(j);
+                       if (pair1.equals(pair2)) {
+                               intersection++;
+                               pairs2.remove(j);
+                               break;
+                       }
+               }
+       }
+       return (2.0 * intersection) / union_;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Among the defined properties, returns the one more similar to String
+ * property
+ */
+private String getSimilarProperty(String property)
+{
+       String bestProperty = null;
+       double bestValue = 0.0;
+       Enumeration e = config.keys();
+       while (e.hasMoreElements()) {
+               String key = (String) e.nextElement();
+               double compare = compareStrings(key, property);
+               if (compare > bestValue) {
+                       bestValue = compare;
+                       bestProperty = key;
+               }
+       }
+       return bestProperty;
+}
+
+//-------------------------------------------------------------------
+
+private void manageDefault(String name, Object def, 
+               RuntimeException e)
+{
+       debug(name, "" + def + " (DEFAULT)");
+       if (check) {
+               System.out.println("Warning: Property " + name + " = " + 
+                               def + " (DEFAULT)");
+       }
+       if (e instanceof MissingParameterException) {
+               // Do nothing
+       } else {
+               manageException(name, e);
+       }
+}
+
+//-------------------------------------------------------------------
+
+private void manageException(String name, RuntimeException e)
+{
+       if (check) {
+               if (e instanceof MissingParameterException) {
+                       // Print just the short message in this case
+                       System.out.println("Error: " + 
+                                       ((MissingParameterException) e).getShortMessage());
+               } else if (e instanceof IllegalParameterException) {
+                       // Print just the short message in this case
+                       System.out.println("Error: " + 
+                                       ((IllegalParameterException) e).getShortMessage());
+               } else {
+                       System.out.println("Error: " + e.getMessage());
+               }
+       } else {
+               throw e;
+       }
+}
+
+//-------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/config/ConfigProperties.java b/contrib/psg/src/peersim/config/ConfigProperties.java
new file mode 100644 (file)
index 0000000..4f36892
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.config;
+
+import java.util.Properties;
+import java.io.*;
+
+/**
+* Class for handling configuration files. Extends the functionality
+* of Properties by handling files, system resources and command lines.
+*/
+public class ConfigProperties extends Properties {
+
+
+// =========== Public Constructors ===================================
+// ===================================================================
+
+
+/**
+* Calls super constructor.
+*/
+public ConfigProperties() { super(); }
+
+// -------------------------------------------------------------------
+
+/**
+* Constructs a ConfigProperty object from a parameter list.
+* The algorithm is as follows: first <code>resource</code> is used to attempt
+* loading default values from the given system resource.
+* Then all Strings in <code>pars</code> are processed in the order they
+* appear in the array. For <code>pars[i]</code>, first a property file
+* with the name <code>pars[i]</code> is attempted to be loaded. If the file
+* does not exist or loading produces any other IOException, <code>pars[i]</code>
+* is interpreted as a property definition, and it is set.
+* <p>
+* A little inconvenience is that if <code>pars[i]</code> is supposed to be 
+* a command line argument, but it is a valid filename at the same time by
+* accident, the algorithm will process it as a file instead of a command line
+* argument. The caller must take care of that.
+* <p>
+* No exceptions are thrown, instead error messages are written to the
+* standard error. Users who want a finer control should use
+* the public methods of this class.
+*
+* @param pars The (probably command line) parameter list.
+* @param resource The name of the system resource that contains the
+* defaults. null if there isn't any.
+* 
+*/
+public ConfigProperties( String[] pars, String resource ) {
+       
+       try
+       {
+               if( resource != null )
+               {
+                       loadSystemResource(resource);
+                       System.err.println("ConfigProperties: System resource "
+                       +resource+" loaded.");
+               }
+       }
+       catch( Exception e )
+       {
+               System.err.println("ConfigProperties: " + e );
+       }
+       
+       if( pars == null || pars.length == 0 ) return;
+       
+       for (int i=0; i < pars.length; i++)
+       {
+               try
+               {
+                       load( pars[i] );
+                       System.err.println(
+                               "ConfigProperties: File "+pars[i]+" loaded.");
+                       pars[i] = "";
+               }
+               catch( IOException e )
+               {
+                       try
+                       {
+                               loadPropertyString( pars[i] );
+                               System.err.println("ConfigProperties: Property '" +
+                                       pars[i] + "' set.");
+                       }
+                       catch( Exception e2 )
+                       {
+                               System.err.println("ConfigProperties: " + e2 );
+                       }
+               }
+               catch( Exception e )
+               {
+                       System.err.println("ConfigProperties: " + e );
+               }
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Constructs a ConfigProperty object by loading a file by calling
+* {@link #load}.
+* @param fileName The name of the configuration file.
+*/
+public ConfigProperties( String fileName ) throws IOException {
+
+       load( fileName );
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Calls super constructor.
+*/
+public ConfigProperties( Properties props ) {
+
+       super( props );
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Calls {@link #ConfigProperties(String[],String)} with resource set to null.
+*/
+public ConfigProperties( String[] pars ) {
+
+       this( pars, null );
+}
+
+
+// =========== Public methods ========================================
+// ===================================================================
+
+
+/**
+* Loads given file. Calls <code>Properties.load</code> with a file
+* input stream to the given file.
+*/
+public void load( String fileName ) throws IOException {
+
+       FileInputStream fis = new FileInputStream( fileName );
+       load( fis );
+       fis.close();
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Adds the properties from the given property file. Searches in the class path
+* for the file with the given name.
+*/
+public void loadSystemResource( String n ) throws IOException {
+       
+       ClassLoader cl = getClass().getClassLoader();
+       load( cl.getResourceAsStream( n ) );
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Appends a property defined in the given string.
+* The string is considered as a property file line.
+* It is converted to a byte array according to the
+* default character encoding and then loaded by the
+* <code>Properties.load</code> method. This means that the ISO-8859-1
+* (or compatible) encoding is assumed.
+*/
+public void loadPropertyString( String prop ) throws IOException {
+
+       StringBuffer sb = new StringBuffer();
+       sb.append( prop ).append( "\n" );
+       load( new ByteArrayInputStream(sb.toString().getBytes()) );
+}
+}
+
diff --git a/contrib/psg/src/peersim/config/Configuration.java b/contrib/psg/src/peersim/config/Configuration.java
new file mode 100644 (file)
index 0000000..4188111
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+import java.util.*;
+
+/**
+ * Fully static class to store configuration information. It defines a
+ * method, {@link #setConfig(Properties)}, to set configuration data. This
+ * method is called by the simulator engines as the very first thing they
+ * do. It can be called only once, after that the class becomes read only.
+ * All components can then access this configuration and utility methods to
+ * read property values based on their names.
+ * <p>
+ * The design of this class also hides the actual implementation of the
+ * configuration which can be Properties, XML, whatever. Currently only
+ * Properties is supported.
+ * <p>
+ * Apart from storing (name,value) pairs, this class also does some
+ * processing, and offers some utility functions. This extended
+ * functionality consists of the following: reading values with type
+ * checking, ordering of entries, pre-processing protocol names, parsing
+ * expressions, resolving underspecified classnames, and finally some basic
+ * debugging possibilities. We discuss these in the following.
+ * <p>
+ * Note that the configuration is initialized using a Properties object.
+ * The class of this object might implement some additional pre-processing
+ * on the file or provide an extended syntax for defining property files.
+ * See {@link ParsedProperties} for more details. This is the class that is
+ * currently used by simulation engines.
+ * <h3>Typed reading of values</h3>
+ * Properties can have arbitrary values of type String. This class offers a
+ * set of read methods that perform the appropriate conversion of the
+ * string value to the given type, eg long. They also allow for specifying
+ * default values in case the given property is not specified.
+ * <h3>Resolving class names</h3>
+ * 
+ * The possibilities for the typed reading of a value includes interpreting
+ * the value as a class name. In this case an object will be constructed.
+ * It is described at method {@link #getInstance(String)} how this is
+ * achieved exactly. What needs to be noted here is that the property value
+ * need not be a fully specified classname. It might contain only the short
+ * class name without the package specification. In this case, it is
+ * attempted to locate a class with that name in the classpath, and if a
+ * unique class is found, it will be used. This simplifies the
+ * configuration files and also allows to remove their dependence on the
+ * exact location of the class.
+ * 
+ * <h3>Components and their ordering</h3>
+ * The idea of the configuration is that it mostly contains components and
+ * their descriptions (parameters). Although this class is blind to the
+ * semantics of these components, it offers some low level functionality
+ * that helps dealing with them. This functionality is based on the
+ * assumption that components have a type and a name. Both types and names
+ * are strings of alphanumeric and underscore characters. For example,
+ * {@value #PAR_PROT} is a type, "foo" can be a name. Method
+ * {@link #getNames} allow the caller to get the list of names for a given
+ * type. Some other methods, like {@link #getInstanceArray} use this list
+ * to return a list of components.
+ * 
+ * <p>
+ * Assuming the configuration is in Properties format (which is currently
+ * the only format available) component types and names are defined as
+ * follows. Property names containing two non-empty words separated by one
+ * dot (".") character are treated specially (the words contain word
+ * characters: alphanumeric and underscore ("_")). The first word will be
+ * the type, and the second is the name of a component. For example,
+ * 
+ * <pre>
+ *   control.conn ConnectivityObserver
+ *   control.1 WireKOut
+ *   control.2 PrintGraph
+ * </pre>
+ * 
+ * defines control components of names "conn","1" an "2" (arguments of the
+ * components not shown). When {@link #getNames} or
+ * {@link #getInstanceArray} are called, eg
+ * <code>getNames("control")</code>, then the order in which these are
+ * returned is alphabetical:
+ * <code>["control.1","control.2","control.conn"]</code>. If you are not
+ * satisfied with lexicographic order, you can specify the order in this
+ * way.
+ * 
+ * <pre>
+ *   order.control 1,conn,2
+ * </pre>
+ * 
+ * where the names are separated by any non-word character (non
+ * alphanumeric or underscore). If not all names are listed then the given
+ * order is followed by alphabetical order of the rest of the items, e.g.
+ * 
+ * <pre>
+ *   order.control 2
+ * </pre>
+ * 
+ * results in <code>["control.2","control.1","control.conn"]</code>.
+ * <p>
+ * It is also possible to exclude elements from the list, while ordering
+ * them. The syntax is identical to that of the above, only the parameter
+ * name begins with <code>include</code>. For example
+ * 
+ * <pre>
+ *   include.control conn 2
+ * </pre>
+ * 
+ * will result in returning <em>only</em> <code>control.conn</code> and
+ * <code>control.2</code>, in this order. Note that for example the
+ * empty list results in a zero length array in this case.
+ * <em>Important!</em> If include is defined then ordering is ignored.
+ * That is, include is stronger than order.
+ * <h3>Protocol names</h3>
+ * As mentioned, the configuration is generally blind to the actual names
+ * of the components. There is an exception: the components of type
+ * {@value #PAR_PROT}. These are pre-processed a bit to enhance
+ * performance: protocol names are mapped to numeric protocol identifiers.
+ * The numeric identifier of a protocol is its index in the array returned
+ * by {@link #getNames}. See above how to control this order. The numeric
+ * identifiers then can be looked up based on the name and vice versa.
+ * Besides, the identifier can be directly requested based on a property
+ * name when the protocol name is the value of a property which is
+ * frequently the case.
+ * <p>
+ * <h3>Expressions</h3>
+ * Numeric property values can be complex expressions, that are parsed
+ * using <a href="http://www.singularsys.com/jep/">JEP</a>. You can write
+ * expression using the syntax that you can find <a
+ * href="http://www.singularsys.com/jep/doc/html/op_and_func.html"> here</a>.
+ * For example,
+ * 
+ * <pre>
+ *   MAG 2
+ *   SIZE 2&circ;MAG
+ * </pre>
+ * 
+ * SIZE=4. You can also have complex expression trees like this:
+ * 
+ * <pre>
+ *   A B+C
+ *   B D+E
+ *   C E+F
+ *   D 1
+ *   E F
+ *   F 2
+ * </pre>
+ * 
+ * that results in A=7, B=3, C=4, D=1, E=2, F=2
+ * 
+ * <p>
+ * Expressions like "sub-expression op sub-expression" are computed based
+ * on the type of the sub-expressions. If both sub-expressions are integer,
+ * the computation is done using integer arithmetics and the result is an
+ * integer. So, for example, 5/2 returns 2. If one of the sub-expression is
+ * floating point, the computation is based on floating-point arithmetics
+ * (double precision) and the result is a floating point value. So, for
+ * example, 5.0/2 returns 2.5.
+ * 
+ * <p>
+ * Expressions are parsed recursively. Note that no optimization is done,
+ * so expression F is evaluated three times here (due to the fact that
+ * appears twice in C and once in B). But since properties are read just
+ * once at initialization, this is not a performance problem.
+ * 
+ * <p>
+ * Finally, recursive definitions are not allowed (and without function
+ * definitions, they make no sense). Since it is difficult to discover
+ * complex recursive chains, a simple trick is used: if the depth of
+ * recursion is greater than a given threshold (configurable, currently
+ * {@value #DEFAULT_MAXDEPTH}, an error message is printed. This avoids to
+ * fill the stack, that results in an anonymous OutOfMemoryError. So, if
+ * you write
+ * 
+ * <pre>
+ *   overlay.size SIZE
+ *   SIZE SIZE-1
+ * </pre>
+ * 
+ * you get an error message: Parameter "overlay.size": Probable recursive
+ * definition - exceeded maximum depth {@value #DEFAULT_MAXDEPTH}
+ * 
+ * <h3>Debug</h3>
+ * 
+ * It is possible to obtain debug information about the configuration
+ * properties by activating special configuration properties.
+ * <p>
+ * If property {@value #PAR_DEBUG} is defined, each config property and the
+ * associated value are printed. Properties that are not present in the
+ * config file but have default values are postfixed with the string
+ * "(DEFAULT)".
+ * <p>
+ * If property {@value #PAR_DEBUG} is defined and it is equal to
+ * {@value #DEBUG_EXTENDED}, information about the configuration method
+ * invoked, and where this method is invoked, is also printed. If it is
+ * equal to {@value #DEBUG_FULL}, all the properties are printed, even if
+ * they are not read.
+ * <p>
+ * Each line printed by this debug feature is prefixed by the string
+ * "DEBUG".
+ * 
+ * <h3>Use of brackets</h3>
+ * 
+ * For the sake of completeness, we mention it here that if this class is
+ * initialized using {@link ParsedProperties}, then it is possible to use
+ * some more compressed format to specify the components. See
+ * {@link ParsedProperties#load}.
+ * 
+ */
+public class Configuration
+{
+
+// =================== static fields =================================
+// ===================================================================
+
+/** Default max depth limit to avoid recursive definitions */
+public static final int DEFAULT_MAXDEPTH = 100;
+
+/**
+ * The debug level for the configuration. If defined, a line is printed for
+ * each configuration parameter read. If defined and equal to
+ * {@value #DEBUG_EXTENDED}, additional context information for debug is
+ * printed. If defined and equal to {@value #DEBUG_FULL}, all the
+ * configuration properties are printed at the beginning, not just when
+ * they are called.
+ * @config
+ */
+static final String PAR_DEBUG = "debug.config";
+
+/**
+ * If parameter {@value #PAR_DEBUG} is equal to this string, additional
+ * context information for debug is printed.
+ */
+static final String DEBUG_EXTENDED = "context";
+
+/**
+ * If parameter {value #PAR_DEBUG} is equal to this string, all the
+ * configuration properties are printed at the beginning, not just when
+ * they are called.
+ */
+static final String DEBUG_FULL = "full";
+
+/**
+ * The maximum depth for expressions. This is a simple mechanism to avoid
+ * unbounded recursion. The default is {@value #DEFAULT_MAXDEPTH}, and you
+ * probably don't want to change it.
+ * @config
+ */
+static final String PAR_MAXDEPTH = "expressions.maxdepth";
+
+/**
+ * Used to configure ordering of the components. Determines the ordering in
+ * the array as returned by {@link #getNames}. See the general description
+ * of {@link Configuration} for details.
+ * @config
+ */
+static final String PAR_ORDER = "order";
+
+/**
+ * Used to configure ordering of the components. Determines the ordering in
+ * the array as returned by {@link #getNames}, and can bu used to also
+ * exclude elements. See the general description of {@link Configuration}
+ * for details.
+ * @config
+ */
+static final String PAR_INCLUDE = "include";
+
+// XXX it's ugly because it replicates the definition of Node.PAR_PROT, but
+// this would be the only dependence on the rest of the core...
+/**
+ * The type name of components describing protocols. This is the only point
+ * at which the class is not blind to the actual semantics of the
+ * configuration.
+ */
+static final String PAR_PROT = "protocol";
+
+/**
+ * The properties object that stores all configuration information.
+ */
+private static ConfigContainer config = null;
+
+// =================== initialization ================================
+// ===================================================================
+
+/** to prevent construction */
+private Configuration()
+{
+}
+
+// =================== static public methods =========================
+// ===================================================================
+
+/**
+ * Sets the system-wide configuration in Properties format. It can be
+ * called only once. After that the configuration becomes unmodifiable
+ * (read only). If modification is attempted, a RuntimeException is thrown
+ * and no change is made.
+ * @param p
+ *          The Properties object containing configuration info
+ */
+public static void setConfig(Properties p)
+{
+       if (config != null) {
+               throw new RuntimeException("Setting configuration was attempted twice.");
+       }
+       config = new ConfigContainer(p, false);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Sets the system-wide configuration in Properties format. It can be
+ * called only once. After that the configuration becomes unmodifiable
+ * (read only). If modification is attempted, a RuntimeException is thrown
+ * and no change is made.
+ * @param p
+ *          The Properties object containing configuration info
+ */
+public static void setConfig(Properties p, boolean check)
+{
+       if (config != null) {
+               throw new RuntimeException("Setting configuration was attempted twice.");
+       }
+       config = new ConfigContainer(p, check);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * @return true if and only if name is a specified (existing) property.
+ */
+public static boolean contains(String name)
+{
+       return config.contains(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public static boolean getBoolean(String name, boolean def)
+{
+       return config.getBoolean(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given property. If not found, or the value is empty string then
+ * throws a {@link MissingParameterException}. Empty string is not
+ * accepted as false due to the similar function of {@link #contains} which
+ * returns true in that case. True is returned if the lowercase value of
+ * the property is "true", otherwise false is returned.
+ * @param name
+ *          Name of configuration property
+ */
+public static boolean getBoolean(String name)
+{
+       return config.getBoolean(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public static int getInt(String name, int def)
+{
+       return config.getInt(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ *          Name of configuration property
+ */
+public static int getInt(String name)
+{
+       return config.getInt(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public static long getLong(String name, long def)
+{
+       return config.getLong(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ *          Name of configuration property
+ */
+public static long getLong(String name)
+{
+       return config.getLong(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public static double getDouble(String name, double def)
+{
+       return config.getDouble(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * MissingParameterException.
+ * @param name
+ *          Name of configuration property
+ */
+public static double getDouble(String name)
+{
+       return config.getDouble(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public static String getString(String name, String def)
+{
+       return config.getString(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * MissingParameterException. Removes trailing whitespace characters.
+ * @param name
+ *          Name of configuration property
+ */
+public static String getString(String name)
+{
+       return config.getString(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads the given property from the configuration interpreting it as a
+ * protocol name. Returns the numeric protocol identifier of this protocol
+ * name. See the discussion of protocol name at {@link Configuration} for
+ * details on how this numeric id is calculated
+ * 
+ * @param name
+ *          Name of configuration property
+ * @return the numeric protocol identifier associated to the value of the
+ *         property
+ */
+public static int getPid(String name)
+{
+       return config.getPid(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Calls {@link #getPid(String)}, and returns the default if no property
+ * is defined with the given name.
+ * 
+ * @param name
+ *          Name of configuration property
+ * @param pid
+ *          the default protocol identifier
+ * @return the numeric protocol identifier associated to the value of the
+ *         property, or the default if not defined
+ */
+public static int getPid(String name, int pid)
+{      
+       return config.getPid(name, pid);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns the numeric protocol identifier of the given protocol name.
+ * 
+ * @param protname
+ *          the protocol name.
+ * @return the numeric protocol identifier associated to the protocol name
+ */
+public static int lookupPid(String protname)
+{
+       return config.lookupPid(protname);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns the name of a protocol that has the given identifier.
+ * <p>
+ * Note that this is not a constant time operation in the number of
+ * protocols, although typically there are very few protocols defined.
+ * 
+ * @param pid
+ *          numeric protocol identifier.
+ * @return name of the protocol that has the given id. null if no protocols
+ *         have the given id.
+ */
+public static String lookupPid(int pid)
+{
+       return config.lookupPid(pid);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}. When creating the Class object, a
+ * few attempts are done to resolve the classname. See
+ * {@link Configuration} for details.
+ * @param name
+ *          Name of configuration property
+ */
+public static Class getClass(String name)
+{
+       return config.getClass(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ * @see #getClass(String)
+ */
+public static Class getClass(String name, Class def)
+{
+       return config.getClass(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property for a class name. It returns an
+ * instance of the class. The class must implement a constructor that takes
+ * a String as an argument. The value of this string will be <tt>name</tt>.
+ * The constructor of the class can see the configuration so it can make
+ * use of this name to read its own parameters from it.
+ * @param name
+ *          Name of configuration property
+ * @throws MissingParameterException
+ *           if the given property is not defined
+ * @throws IllegalParameterException
+ *           if there is any problem creating the instance
+ */
+public static Object getInstance(String name)
+{
+       return config.getInstance(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property for a class name. It returns an
+ * instance of the class. The class must implement a constructor that takes
+ * a String as an argument. The value of this string will be <tt>name</tt>.
+ * The constructor of the class can see the configuration so it can make
+ * use of this name to read its own parameters from it.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          The default object that is returned if there is no property
+ *          defined with the given name
+ * @throws IllegalParameterException
+ *           if the given name is defined but there is a problem creating
+ *           the instance.
+ */
+public static Object getInstance(String name, Object def)
+{
+       return config.getInstance(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * It returns an array of class instances. The instances are constructed by
+ * calling {@link #getInstance(String)} on the names returned by
+ * {@link #getNames(String)}.
+ * @param name
+ *          The component type (i.e. prefix of the list of configuration
+ *          properties) which will be passed to {@link #getNames(String)}.
+ */
+public static Object[] getInstanceArray(String name)
+{
+       return config.getInstanceArray(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns an array of names prefixed by the specified name. The array is
+ * sorted as follows. If there is no config entry
+ * <code>{@value #PAR_INCLUDE}+"."+name</code> or
+ * <code>{@value #PAR_ORDER}+"."+name</code> then the order is
+ * alphabetical. Otherwise this entry defines the order. For more
+ * information see {@link Configuration}.
+ * @param name
+ *          the component type (i.e., the prefix)
+ * @return the full property names in the order specified by the
+ *         configuration
+ */
+public static String[] getNames(String name)
+{
+       return config.getNames(name);
+}
+
+}
diff --git a/contrib/psg/src/peersim/config/FastConfig.java b/contrib/psg/src/peersim/config/FastConfig.java
new file mode 100644 (file)
index 0000000..d2eba1b
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+/**
+ * Reads configuration regarding relations between protocols.
+ * 
+ * Technically, this class is not necessary because protocols could
+ * access the configuration directly. However, it provides much faster
+ * access to "linkable" and "transport" information, enhancing runtime speed.
+ *
+ * This class is a static singleton and is initialized only when first accessed.
+ * During initialization it reads and caches the configuration info it handles.
+ */
+public class FastConfig
+{
+
+// ======================= fields ===========================================
+// ===========================================================================
+
+/**
+ * Parameter name in configuration that attaches a linkable protocol to a
+ * protocol. The property can contain multiple protocol names, in one line,
+ * separated by non-word characters (e.g. whitespace or ",").
+ * @config
+ */
+private static final String PAR_LINKABLE = "linkable";
+
+/**
+ * Parameter name in configuration that attaches a transport layer protocol to a
+ * protocol.
+ * @config
+ */
+private static final String PAR_TRANSPORT = "transport";
+
+/**
+ * This array stores the protocol ids of the {@link peersim.core.Linkable}
+ * protocols that are linked to the protocol given by the array index.
+ */
+protected static final int[][] links;
+
+/**
+ * This array stores the protocol id of the {@link peersim.transport.Transport}
+ * protocol that is linked to the protocol given by the array index.
+ */
+protected static final int[] transports;
+
+
+// ======================= initialization ===================================
+// ==========================================================================
+
+
+/**
+ * This static initialization block reads the configuration for information that
+ * it understands. Currently it understands property {@value #PAR_LINKABLE}
+ * and {@value #PAR_TRANSPORT}.
+ * 
+ * Protocols' linkable and transport definitions are prefetched
+ * and stored in arrays, to enable fast access during simulation.
+ *
+ * Note that this class does not perform any type checks. The purpose of the
+ * class is purely to speed up access to linkable and transport information,
+ * by providing a fast alternative to reading directly from the
+ * <code>Configuration</code> class.
+ */
+static {
+       String[] names = Configuration.getNames(Configuration.PAR_PROT);
+       links = new int[names.length][];
+       transports = new int[names.length];
+       for (int i = 0; i < names.length; ++i)
+       {
+               if (Configuration.contains(names[i] + "." + PAR_LINKABLE))
+               {
+                       // get string of linkables
+                       String str = Configuration.getString(names[i] + "." + PAR_LINKABLE);
+                       // split around non-word characters
+                       String[] linkNames = str.split("\\W+");
+                       links[i] = new int[linkNames.length];
+                       for (int j=0; j<linkNames.length; ++j)
+                               links[i][j] = Configuration.lookupPid(linkNames[j]);
+               }               
+               else
+                       links[i] = new int[0]; // empty set
+
+               if (Configuration.contains(names[i] + "." + PAR_TRANSPORT))
+                       transports[i] = 
+                       Configuration.getPid(names[i] + "." + PAR_TRANSPORT);
+               else
+                       transports[i] = -1;
+       }
+}
+
+// ---------------------------------------------------------------------
+
+/** to prevent construction */
+private FastConfig() {}
+
+// ======================= methods ==========================================
+// ==========================================================================
+
+
+/**
+ * Returns true if the given protocol has at least one linkable protocol
+ * associated with it, otherwise false.
+ */
+public static boolean hasLinkable(int pid) { return numLinkables(pid) > 0; }
+
+// ---------------------------------------------------------------------
+
+/**
+ * Returns the number of linkable protocols associated with a given protocol.
+ */
+public static int numLinkables(int pid) { return links[pid].length; }
+
+// ---------------------------------------------------------------------
+
+/**
+ * Returns the protocol id of the <code>linkIndex</code>-th linkable used by
+ * the protocol identified by pid. Throws an
+ * IllegalParameterException if there is no linkable associated with the given
+ * protocol: we assume here that this happens when the configuration is
+ * incorrect.
+ */
+public static int getLinkable(int pid, int linkIndex)
+{
+       if (linkIndex >= numLinkables(pid)) {
+               String[] names = Configuration.getNames(Configuration.PAR_PROT);
+               throw new IllegalParameterException(names[pid],
+                       "Protocol " + pid + " has no "+PAR_LINKABLE+
+                       " parameter with index" + linkIndex);
+       }
+       return links[pid][linkIndex];
+}
+
+//---------------------------------------------------------------------
+
+/**
+ * Invokes <code>getLinkable(pid, 0)</code>.
+ */
+public static int getLinkable(int pid)
+{
+       return getLinkable(pid, 0);
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * Returns true if the given protocol has a transport protocol associated with
+ * it, otherwise false.
+ */
+public static boolean hasTransport(int pid)
+{
+       return transports[pid] >= 0;
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * Returns the id of the transport protocol used by the protocol identified
+ * by pid.
+ * Throws an IllegalParameterException if there is no transport associated
+ * with the given protocol: we assume here that his happens when the
+ * configuration is incorrect.
+ */
+public static int getTransport(int pid)
+{
+       if (transports[pid] < 0) {
+               String[] names = Configuration.getNames(Configuration.PAR_PROT);
+               throw new IllegalParameterException(names[pid],
+               "Protocol " + pid + " has no "+PAR_TRANSPORT + " parameter");
+       }
+       return transports[pid];
+}
+
+}
diff --git a/contrib/psg/src/peersim/config/IllegalParameterException.java b/contrib/psg/src/peersim/config/IllegalParameterException.java
new file mode 100644 (file)
index 0000000..1285350
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+/**
+* Exception thrown to indicate that a
+* configuration property has an invalid value. It is thrown by
+* several methods in {@link Configuration} and can be thrown by any
+* component that reads the configuration.
+*/
+public class IllegalParameterException extends RuntimeException {
+
+// ================== initialization =====================================
+// =======================================================================
+
+/**
+* Calls super constructor. It passes a string message which is the given
+* message, prefixed with the given property name.
+* @param name Name of configuration property that is invalid
+* @param message Additional info about why the value is invalid
+*/
+public IllegalParameterException(String name, String message) {
+
+       super("Parameter \"" + name + "\": " + message); 
+}
+
+// ================== methods ============================================
+// =======================================================================
+
+/**
+* Extends message with info from stack trace.
+* It tries to guess what class called {@link Configuration} and
+* adds relevant info from the stack trace about it to the message.
+*/
+public String getMessage() {
+
+       StackTraceElement[] stack = getStackTrace();
+
+       // Search the element that invoked Configuration
+       // It's the first whose class is different from Configuration
+       int pos;
+       for (pos=0; pos < stack.length; pos++)
+       {
+               if (!stack[pos].getClassName().equals(
+                       Configuration.class.getName()))
+                       break;
+       }
+
+       return super.getMessage()+"\nAt "+
+               getStackTrace()[pos].getClassName()+"."+
+               getStackTrace()[pos].getMethodName()+":"+
+               getStackTrace()[pos].getLineNumber();
+}
+
+/**
+ * Returns the exception message without stack trace information
+ */
+public String getShortMessage()
+{
+       return super.getMessage();
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/config/MissingParameterException.java b/contrib/psg/src/peersim/config/MissingParameterException.java
new file mode 100644 (file)
index 0000000..58b85cd
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+/**
+* Exception thrown to indicate that a
+* configuration property is not defined. It is thrown exclusively by
+* {@link Configuration}, since it is the only class that has access to the
+* set of defined properties. 
+ */
+public class MissingParameterException extends RuntimeException {
+
+// ================== initialization =====================================
+// =======================================================================
+
+MissingParameterException(String name) {
+
+       super("Parameter \"" + name + "\" not found.");
+}
+
+MissingParameterException(String name, String motivation) {
+
+       super("Parameter \"" + name + "\" not found " + motivation);
+}
+
+// ================== methods ============================================
+// =======================================================================
+
+/**
+* Extends message with info from stack trace.
+* It tries to guess what class called {@link Configuration} and
+* adds relevant info from the stack trace about it to the message.
+*/
+public String getMessage() {
+       
+       StackTraceElement[] stack = getStackTrace();
+
+       // Search the element that invoked Configuration
+       // It's the first whose class is different from Configuration
+       int pos;
+       for (pos=0; pos < stack.length; pos++) {
+               if (!stack[pos].getClassName().equals(
+                       Configuration.class.getName()))
+                       break;
+       }
+
+       return super.getMessage()+"\nAt "+
+               getStackTrace()[pos].getClassName()+"."+
+               getStackTrace()[pos].getMethodName()+":"+
+               getStackTrace()[pos].getLineNumber();
+}
+
+/**
+ * Returns the exception message without stack trace information
+ */
+public String getShortMessage()
+{
+       return super.getMessage();
+}
+
+}
diff --git a/contrib/psg/src/peersim/config/NullPrintStream.java b/contrib/psg/src/peersim/config/NullPrintStream.java
new file mode 100644 (file)
index 0000000..6124922
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+import java.io.*;
+
+/**
+ * A subclass of PrintStream whose methods ignore the content 
+ * being written. 
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.1 $
+ */
+public class NullPrintStream extends PrintStream
+{
+
+/**
+ * Creates a null print stream that does not print anything.
+ */
+public NullPrintStream()
+{
+       super(System.out);
+}
+
+/**
+ * This methods does not print anything.
+ */
+public synchronized void write(byte[] b, int off, int len)
+{
+}
+
+/**
+ * This methods does not print anything.
+ */
+public synchronized void write(int b)
+{
+}
+
+/**
+ * This methods does not print anything.
+ */
+private void printLine()
+{
+}
+
+}
diff --git a/contrib/psg/src/peersim/config/Operators.java b/contrib/psg/src/peersim/config/Operators.java
new file mode 100644 (file)
index 0000000..1d5d523
--- /dev/null
@@ -0,0 +1,163 @@
+/*\r
+ * Copyright (c) 2003-2005 The BISON Project\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU Lesser General Public License version 2 as\r
+ * published by the Free Software Foundation.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+ *\r
+ */\r
+package peersim.config;\r
+import java.math.*;\r
+import org.lsmp.djep.groupJep.groups.*;\r
+import org.lsmp.djep.groupJep.interfaces.*;\r
+\r
+/**\r
+ * This class implements the <code>Group</code> interface of JEP,\r
+ * enabling the configuration system to read integers with arbitrary \r
+ * length. \r
+ */\r
+public class Operators extends Group implements IntegralDomainI,HasDivI,\r
+       OrderedSetI,HasModI,HasPowerI {\r
+       \r
+\r
+       /**\r
+        * Operations on the reals (Implemented as BigInteger).\r
+        */\r
+       public Operators() {\r
+       }\r
+\r
+       public Number getZERO() {\r
+               return BigInteger.ZERO;\r
+       }\r
+\r
+       public Number getONE() {\r
+               return BigInteger.ONE;\r
+       }\r
+\r
+       public Number getInverse(Number num) {\r
+               if (num instanceof BigInteger) {\r
+                       BigInteger a = (BigInteger) num;\r
+                       return a.negate();\r
+               } else {\r
+                       return -num.doubleValue();\r
+               }\r
+       }\r
+\r
+       public Number add(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() + num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.add(b);\r
+               }\r
+       }\r
+\r
+       public Number sub(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() - num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.subtract(b);\r
+               }\r
+       }\r
+\r
+       public Number mul(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() * num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.multiply(b);\r
+               }\r
+       }\r
+\r
+       public Number div(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() / num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.divide(b);\r
+               }\r
+       }\r
+\r
+        \r
+       public Number mod(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() % num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.remainder(b);\r
+               }\r
+       }\r
+       \r
+       public Number pow(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return Math.pow(num1.doubleValue(), num2.doubleValue());\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.pow(b.intValue());\r
+               }\r
+       }\r
+       \r
+       public boolean equals(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() == num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.equals(b);\r
+               }\r
+       }\r
+       \r
+       public int compare(Number num1,Number num2)     {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       double n1 = num1.doubleValue();\r
+                       double n2 = num2.doubleValue();\r
+                       return (n1 < n2 ? -1 : (n1 == n2 ? 0 : 1));\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.compareTo(b);\r
+               }\r
+       }\r
+\r
+       public Number valueOf(String str) {\r
+               try {\r
+                       return new BigInteger(str);\r
+               } catch (NumberFormatException e) {\r
+                       return new Double(str);\r
+               }\r
+       }\r
+       \r
+       public String toString() { return ""; }\r
+}\r
diff --git a/contrib/psg/src/peersim/config/ParsedProperties.java b/contrib/psg/src/peersim/config/ParsedProperties.java
new file mode 100644 (file)
index 0000000..9a58e41
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.config;
+
+import java.io.*;
+import java.util.*;
+
+/**
+* Extends the class {@link ConfigProperties} with basic parsing capabilities.
+* @see #load
+*/
+public class ParsedProperties extends ConfigProperties {
+
+//================= variables ======================================
+//==================================================================
+
+// ================= initialization =================================
+// ==================================================================
+
+/**
+* Calls super constructor.
+* @see ConfigProperties#ConfigProperties(String[])
+*/
+public ParsedProperties( String[] pars ) {
+
+       super( pars );
+}
+
+// ------------------------------------------------------------------
+
+/**
+* Calls super constructor.
+* @see ConfigProperties#ConfigProperties(String)
+*/
+public ParsedProperties( String filename ) throws IOException {
+
+       super( filename );
+}
+
+
+// =========== Public methods ========================================
+// ===================================================================
+
+
+/**
+* Loads given file. It works exactly as <code>Properties.load</code>
+* with a file input stream to the given file, except that the file is parsed
+* the following way allowing to compress some property names
+* using <code>{</code> and <code>}</code>.
+  
+  When a bracket is present, it must
+  be the only non-space element of a line. The last property defined 
+  before the opening bracket define the prefix that is added to all the 
+  properties defined included between brackets.
+  In other words, a construct like this:
+  <pre>
+  control.degree GraphObserver 
+  {
+    protocol newscast
+    undir
+  }
+  </pre>
+  is equivalent to the definition of these three properties:
+  <pre>
+  control.degree GraphObserver 
+  control.degree.protocol newscast
+  control.degree.undir
+  </pre>
+  
+  Nested brackets are possible. The rule of the last property before 
+  the opening bracket applies also to the inside brackets, with
+  the prefix being the complete property definition (so, including
+  the prefix observed before). Example:
+  <pre>
+       control.1 DynamicNetwork
+       {
+         add CRASH
+         substitute
+         init.0 WireKOut 
+         {
+           degree DEGREE
+           protocol 0
+         }
+       }
+  </pre>
+  defines the following properties:
+  <pre>
+       control.1 DynamicNetwork
+       control.1.add CRASH
+       control.1.substitute
+       control.1.init.0 WireKOut 
+       control.1.init.0.degree DEGREE
+       control.1.init.0.protocol 0
+  </pre>
+  
+  <p>
+  Know limitations: 
+  The parsing mechanism is very simple; no complex error messages
+  are provided. In case of missing closing brackets, the method
+  will stop reporting the number of missing brackets. Additional
+  closing brackets (i.e., missing opening brackets) produce an
+  error messages reporting the line where the closing bracket
+  is present. Misplaced brackets (included in lines that
+  contains other characters) are ignored, thus may indirectly produce
+  the previous error messages.
+*/
+public void load( String fileName ) throws IOException {
+
+       /* This set is used to store prefixes that have been associated
+        * to brackets blocks. If a prefix is inserted twice, this means
+        * that there are two blocks referring to the same prefix - 
+        * which may be caused by a commented prefix in the config
+        * file, something like this:
+        * 
+        *  prefix1
+        *  {
+        *    property 1
+        *  }
+        *  #prefix2
+        *  {
+        *    property 2
+        *  }
+        *
+        */
+       Set<String> prefixes = new HashSet<String>();
+       
+       BufferedReader f = 
+               new BufferedReader(new FileReader( fileName ));
+       int lines = 0;
+       parseStream(f, "", 0, lines, prefixes);
+
+       f.close();
+}
+
+// --------------------------------------------------------------------
+
+private int parseStream(BufferedReader f, String prefix, int pars, 
+               int lines, Set prefixes)
+throws IOException {
+
+       if (prefix.equals(".")) {
+               System.err.println("Error at line " + lines + ": bracket block not " +
+                               "associated with any configuration entry");
+               System.exit(1);
+       }
+       if (prefixes.contains(prefix)) {
+               System.err.println("Error at line " + lines + ": multiple bracket " +
+                               "blocks referring to the same configuration entry " + prefix);
+               System.exit(1);
+       } else {
+               prefixes.add(prefix);
+       }
+       
+       boolean complete = true;
+       String part;
+       String line = "";
+       String last = "";
+       while ((part = f.readLine()) != null)
+       {
+               lines++;
+               
+               // Reset line
+               if (complete) line = "";
+               
+               // Check if the line is a comment line
+               // If so, remove the comment
+               int index = part.indexOf('#');
+               if (index >= 0)
+               {
+                       part = part.substring(0, index);
+               } 
+
+               // Check if the line is empty
+               part = part.trim();
+               if ("".equals(part)) continue;
+
+               complete = (part.charAt(part.length()-1) != '\\'); 
+               if (!complete)
+               {  
+                       line = line + part.substring(0, part.length()-2) + " ";
+                       continue;
+               }
+               
+               // Complete the line
+               line = line + part;
+               if (line.equals("{"))
+               {
+                       lines = parseStream(f, last+".", pars+1, lines, prefixes);
+               } 
+               else if (line.equals("}"))
+               {
+                       if (pars == 0)
+                       {
+                               System.err.println(
+                                       "Error: Additional } at line " + lines + 
+                                       " when parsing the configuration file");
+                               System.exit(1);
+                       }
+                       return lines;
+               }
+               else
+               {
+                       // Search the first token
+                       String[] tokens = line.split("[\\s:=]+", 2);
+                       if (tokens.length == 1)
+                       {
+                               setProperty(prefix+tokens[0], "");
+                       }
+                       else
+                       {
+                               setProperty(prefix+tokens[0], tokens[1]);
+                       }
+                       last = prefix + tokens[0];
+               }
+       }
+       if (pars == 1)
+       {
+               System.err.println("Error: One closing bracket ('}') is missing");
+               System.exit(1);
+       } 
+       else if (pars > 1)
+       {
+               System.err.println("Error: " + pars+" closing brackets ('}') are missing");
+               System.exit(1);
+       }
+       return lines;
+}
+
+// --------------------------------------------------------------------
+
+/*
+public static void main(String[] args)
+{
+       java.util.Properties prop = new ParsedProperties(args);
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/core/Cleanable.java b/contrib/psg/src/peersim/core/Cleanable.java
new file mode 100644 (file)
index 0000000..ac14f21
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+/**
+ * This interface must be implemented by protocols that need to release
+ * some references when the fail state of their host node is set to
+ * {@link Fallible#DEAD}. Recall that this fail state means that the node
+ * will never get back online. However, other nodes and protocols might
+ * still have references to these dead nodes and protocols, and this fact
+ * is not always a bug. So implementing this interface allows for removing
+ * stuff that we know is no longer necessary. Especially for linkable
+ * protocols in the presence of churn, this is essential: they typically
+ * have to release their links to other nodes to prevent the formation of
+ * trees of removed nodes with a live reference to the root.
+ */
+public interface Cleanable
+{
+
+/**
+ * Performs cleanup when removed from the network. This is called by the
+ * host node when its fail state is set to {@link Fallible#DEAD}.
+ * It is very important that after calling this method, NONE of the methods
+ * of the implementing object are guaranteed to work any longer.
+ * They might throw arbitrary exceptions, etc. The idea is that after
+ * calling this, typically no one should access this object.
+ * However, as a recommendation, at least toString should be guaranteed to
+ * execute normally, to aid debugging.
+ */
+public void onKill();
+
+}
diff --git a/contrib/psg/src/peersim/core/CommonState.java b/contrib/psg/src/peersim/core/CommonState.java
new file mode 100644 (file)
index 0000000..93b6e21
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+import org.simgrid.msg.Msg;
+
+import peersim.Simulator;
+import peersim.config.*;
+import peersim.util.*;
+import psgsim.PSGPlatform;
+
+/**
+ * This is the common state of the simulation all objects see.
+ * Static singleton. One of its purposes is
+ * simplification of parameter structures and increasing efficiency by putting
+ * state information here instead of passing parameters.
+ *<p>
+ * <em>The set methods should not be used by applications</em>,
+ * they are for system
+ * components. Use them only if you know exactly what you are doing, e.g.
+ * if you are so advanced that you can write your own simulation engine.
+ * Ideally, they should not be visible, but due to the lack of more
+ * flexibility in java access rights, we are forced to make them public.
+ */
+public class CommonState
+{
+
+//======================= constants ===============================
+//=================================================================
+
+/**
+* Constant that can be used as a value of simulation phase.
+* It means that the simulation has finished.
+* @see #getPhase
+*/
+public static final int POST_SIMULATION = 1;
+
+/**
+* Constant that can be used as a value of simulation phase.
+* It means that the simulation phase information has not been set (unknown).
+* @see #getPhase
+*/
+public static final int PHASE_UNKNOWN = 0;
+
+// ======================= fields ==================================
+// =================================================================
+
+/**
+ * Current time. Note that this value is simulator independent, all simulation
+ * models have a notion related to time. For example, in the cycle based model,
+ * the cycle id gives time, while in even driven simulations there is a more
+ * realistic notion of time.
+ */
+private static long time = 0;
+
+/**
+ * The maximal value {@link #time} can ever take.
+ */
+private static long endtime = -1;
+
+/**
+ * Number of used bits in the long representation of time, calculated
+ * based on the endtime.
+ */
+private static int toshift = -1;
+
+/**
+ * Information about where exactly the simulation is.
+ */
+private static int phase = PHASE_UNKNOWN;
+
+/**
+ * The current pid.
+ */
+private static int pid;
+
+/**
+ * The current node.
+ */
+private static Node node;
+
+/**
+* This source of randomness should be used by all components.
+* This field is public because it doesn't matter if it changes
+* during an experiment (although it shouldn't) until no other sources of
+* randomness are used within the system. Besides, we can save the cost
+* of calling a wrapper method, which is important because this is needed
+* very often.
+*/
+public static ExtendedRandom r = null;
+
+
+// ======================== initialization =========================
+// =================================================================
+
+/**
+* Configuration parameter used to define which random generator
+* class should be used. If not specified, the default implementation
+* {@link ExtendedRandom} is used. User-specified random generators 
+* must extend class {@link ExtendedRandom}. 
+* @config
+*/
+public static final String PAR_RANDOM = "random";
+
+/**
+* Configuration parameter used to initialize the random seed.
+* If it is not specified the current time is used.
+* @config
+*/
+public static final String PAR_SEED = "random.seed";
+
+
+/**
+* Initializes the field {@link r} according to the configuration.
+* Assumes that the configuration is already
+* loaded.
+*/
+static {
+       
+       long seed =
+               Configuration.getLong(PAR_SEED,System.currentTimeMillis());
+       initializeRandom(seed);
+}
+
+
+/** Does nothing. To avoid construction but allow extension. */
+protected CommonState() {}
+
+// ======================= methods =================================
+// =================================================================
+
+
+/**
+ * Returns current time. In event-driven simulations, returns the current
+ * time (a long-value).
+ * In cycle-driven simulations, returns the current cycle (a long that
+ * can safely be cast into an integer).
+ */
+public static long getTime()
+{
+       /* if the engine simulator used is PSG (simId=2 */
+       if(Simulator.getSimID()==2)
+               return (long) PSGPlatform.getTime();
+       else
+       return time;
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns current time in integer format. The purpose is to enhance the
+ * performance of protocols (ints are smaller and faster) when absolute
+ * precision is not required. It assumes that endtime has been set via
+ * {@link #setEndTime} by the simulation engine. It uses the endtime for
+ * the optimal mapping to get the maximal precision.
+ * In particular, in the cycle
+ * based model, time is the same as cycle which can be safely cast into
+ * integer, so no precision is lost.
+ */
+public static int getIntTime()
+{
+       return (int)(time>>toshift);
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Sets the current time. 
+ */
+public static void setTime(long t)
+{
+       time = t;
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns endtime.
+ * It is the maximal value {@link #getTime} ever returns. If it's negative, it
+ * means the endtime is not known.
+ */
+public static long getEndTime()
+{
+       return endtime;
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Sets the endtime. 
+ */
+public static void setEndTime(long t)
+{
+       if( endtime >= 0 )
+               throw new RuntimeException("You can set endtime only once");
+       if( t < 0 )
+               throw new RuntimeException("No negative values are allowed");
+               
+       endtime = t;
+       toshift = 32-Long.numberOfLeadingZeros(t);
+       if( toshift<0 ) toshift = 0;
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns the simulation phase. Currently the following phases are
+ * understood.
+ * <ul>
+ * <li>{@link #PHASE_UNKNOWN} phase is unknown</li>
+ * <li>{@link #POST_SIMULATION} the simulation is completed</li>
+ * </ul>
+ */
+public static int getPhase()
+{
+       return phase;
+}
+
+// -----------------------------------------------------------------
+
+public static void setPhase(int p)
+{
+       phase = p;
+}
+
+// -----------------------------------------------------------------
+
+/**
+* Returns the current protocol identifier. In other words, control is
+* held by the indicated protocol on node {@link #getNode}.
+*/
+public static int getPid()
+{
+       return pid;
+}
+
+//-----------------------------------------------------------------
+
+/** Sets the current protocol identifier.*/
+public static void setPid(int p)
+{
+       pid = p;
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns the current node. When a protocol is executing, it is the node
+ * hosting the protocol.
+ */
+public static Node getNode()
+{
+       return node;
+}
+
+//-----------------------------------------------------------------
+
+/** Sets the current node */
+public static void setNode(Node n)
+{
+       node = n;
+}
+
+//-----------------------------------------------------------------
+
+public static void initializeRandom(long seed)
+{
+       if (r == null) {
+               r = (ExtendedRandom) Configuration.getInstance(PAR_RANDOM, new ExtendedRandom(seed));
+       }
+       r.setSeed(seed);
+}
+
+//-----------------------------------------------------------------
+
+/*
+public static void main(String pars[]) {
+       
+       setEndTime(Long.parseLong(pars[0]));
+       setTime(Long.parseLong(pars[1]));
+       System.err.println(getTime()+" "+getIntTime());
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/core/Control.java b/contrib/psg/src/peersim/core/Control.java
new file mode 100644 (file)
index 0000000..7644aa9
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+/**
+ * Generic interface for classes that are responsible for observing or modifying
+ * the ongoing simulation. It is designed to allow maximal flexibility therefore
+ * poses virtually no restrictions on the implementation.
+ */
+public interface Control
+{
+
+/**
+ * Performs arbitrary modifications or reports arbitrary information over the
+ * components.
+ * @return true if the simulation has to be stopped, false otherwise.
+ */
+public boolean execute();
+
+}
diff --git a/contrib/psg/src/peersim/core/Fallible.java b/contrib/psg/src/peersim/core/Fallible.java
new file mode 100644 (file)
index 0000000..089cffe
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.core;
+
+
+/**
+* Instances of classes implementing this interface
+* maintain a fail state, i.e. information about the availability
+* of the object.
+*/
+public interface Fallible {
+
+       /**
+       * Fail state which indicates that the object is operating normally.
+       */
+       public int OK = 0;
+
+       /**
+       * Fail state indicating that the object is dead and recovery is
+       * not possible. When this state is set, it is a good idea to make sure
+       * that the state of the object becomes such that any attempt to
+       * operate on it causes a visible error of some kind.
+       */
+       public int DEAD = 1;
+
+       /**
+       * Fail state indicating that the object is not dead, but is temporarily
+       * not accessible.
+       */
+       public int DOWN = 2;
+
+       /**
+       * Returns the state of this object. Must be one of the constants
+       * defined in interface {@link Fallible}.
+       */
+       public int getFailState();
+       
+       /**
+       * Sets the fails state of this object. Parameter must be one of the
+       * constants defined in interface {@link Fallible}.
+       */
+       public void setFailState(int failState);
+
+       /**
+       * Convenience method to check if the node is up and running
+       * @return must return true if and only if
+       * <code>getFailState()==OK</code>
+       */
+       public boolean isUp();
+}
+
+
diff --git a/contrib/psg/src/peersim/core/GeneralNode.java b/contrib/psg/src/peersim/core/GeneralNode.java
new file mode 100644 (file)
index 0000000..2f2c02e
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.core;
+
+import peersim.config.*;
+
+/**
+* This is the default {@link Node} class that is used to compose the
+* {@link Network}.
+*/
+public class GeneralNode implements Node {
+
+
+// ================= fields ========================================
+// =================================================================
+
+/** used to generate unique IDs */
+private static long counterID = -1;
+
+/**
+* The protocols on this node.
+*/
+protected Protocol[] protocol = null;
+
+/**
+* The current index of this node in the node
+* list of the {@link Network}. It can change any time.
+* This is necessary to allow
+* the implementation of efficient graph algorithms.
+*/
+private int index;
+
+/**
+* The fail state of the node.
+*/
+protected int failstate = Fallible.OK;
+
+/**
+* The ID of the node. It should be final, however it can't be final because
+* clone must be able to set it.
+*/
+private long ID;
+
+// ================ constructor and initialization =================
+// =================================================================
+
+/** Used to construct the prototype node. This class currently does not
+* have specific configuration parameters and so the parameter
+* <code>prefix</code> is not used. It reads the protocol components
+* (components that have type {@value peersim.core.Node#PAR_PROT}) from
+* the configuration.
+*/
+public GeneralNode(String prefix) {
+       
+       String[] names = Configuration.getNames(PAR_PROT);
+       CommonState.setNode(this);
+       ID=nextID();
+       protocol = new Protocol[names.length];
+       for (int i=0; i < names.length; i++) {
+               CommonState.setPid(i);
+               Protocol p = (Protocol) 
+                       Configuration.getInstance(names[i]);
+               protocol[i] = p; 
+       }
+}
+
+
+// -----------------------------------------------------------------
+
+public Object clone() {
+       
+       GeneralNode result = null;
+       try { result=(GeneralNode)super.clone(); }
+       catch( CloneNotSupportedException e ) {} // never happens
+       result.protocol = new Protocol[protocol.length];
+       CommonState.setNode(result);
+       result.ID=nextID();
+       for(int i=0; i<protocol.length; ++i) {
+               CommonState.setPid(i);
+               result.protocol[i] = (Protocol)protocol[i].clone();
+       }
+       return result;
+}
+
+// -----------------------------------------------------------------
+
+/** returns the next unique ID */
+private long nextID() {
+
+       return counterID++;
+}
+
+// =============== public methods ==================================
+// =================================================================
+
+
+public void setFailState(int failState) {
+       
+       // after a node is dead, all operations on it are errors by definition
+       if(failstate==DEAD && failState!=DEAD) throw new IllegalStateException(
+               "Cannot change fail state: node is already DEAD");
+       switch(failState)
+       {
+               case OK:
+                       failstate=OK;
+                       break;
+               case DEAD:
+                       //protocol = null;
+                       index = -1;
+                       failstate = DEAD;
+                       for(int i=0;i<protocol.length;++i)
+                               if(protocol[i] instanceof Cleanable)
+                                       ((Cleanable)protocol[i]).onKill();
+                       break;
+               case DOWN:
+                       failstate = DOWN;
+                       break;
+               default:
+                       throw new IllegalArgumentException(
+                               "failState="+failState);
+       }
+}
+
+// -----------------------------------------------------------------
+
+public int getFailState() { return failstate; }
+
+// ------------------------------------------------------------------
+
+public boolean isUp() { return failstate==OK; }
+
+// -----------------------------------------------------------------
+
+public Protocol getProtocol(int i) { return protocol[i]; }
+
+//------------------------------------------------------------------
+
+public int protocolSize() { return protocol.length; }
+
+//------------------------------------------------------------------
+
+public int getIndex() { return index; }
+
+//------------------------------------------------------------------
+
+public void setIndex(int index) { this.index = index; }
+       
+//------------------------------------------------------------------
+
+/**
+* Returns the ID of this node. The IDs are generated using a counter
+* (i.e. they are not random).
+*/
+public long getID() { return ID; }
+
+//------------------------------------------------------------------
+
+public String toString() 
+{
+       StringBuffer buffer = new StringBuffer();
+       buffer.append("ID: "+ID+" index: "+index+"\n");
+       for(int i=0; i<protocol.length; ++i)
+       {
+               buffer.append("protocol["+i+"]="+protocol[i]+"\n");
+       }
+       return buffer.toString();
+}
+
+//------------------------------------------------------------------
+
+/** Implemented as <code>(int)getID()</code>. */
+public int hashCode() { return (int)getID(); }
+
+}
+
+
diff --git a/contrib/psg/src/peersim/core/IdleProtocol.java b/contrib/psg/src/peersim/core/IdleProtocol.java
new file mode 100644 (file)
index 0000000..dd602d5
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+import peersim.config.Configuration;
+
+/**
+ * A protocol that stores links. It does nothing apart from that.
+ * It is useful to model a static link-structure
+ * (topology). The only function of this protocol is to serve as a source of
+ * neighborhood information for other protocols.
+ */
+public class IdleProtocol implements Protocol, Linkable
+{
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/**
+ * Default init capacity
+ */
+private static final int DEFAULT_INITIAL_CAPACITY = 10;
+
+/**
+ * Initial capacity. Defaults to {@value #DEFAULT_INITIAL_CAPACITY}.
+ * @config
+ */
+private static final String PAR_INITCAP = "capacity";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Neighbors */
+protected Node[] neighbors;
+
+/** Actual number of neighbors in the array */
+protected int len;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+public IdleProtocol(String s)
+{
+       neighbors = new Node[Configuration.getInt(s + "." + PAR_INITCAP,
+                       DEFAULT_INITIAL_CAPACITY)];
+       len = 0;
+}
+
+//--------------------------------------------------------------------------
+
+public Object clone()
+{
+       IdleProtocol ip = null;
+       try { ip = (IdleProtocol) super.clone(); }
+       catch( CloneNotSupportedException e ) {} // never happens
+       ip.neighbors = new Node[neighbors.length];
+       System.arraycopy(neighbors, 0, ip.neighbors, 0, len);
+       ip.len = len;
+       return ip;
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+public boolean contains(Node n)
+{
+       for (int i = 0; i < len; i++) {
+               if (neighbors[i] == n)
+                       return true;
+       }
+       return false;
+}
+
+// --------------------------------------------------------------------------
+
+/** Adds given node if it is not already in the network. There is no limit
+* to the number of nodes that can be added. */
+public boolean addNeighbor(Node n)
+{
+       for (int i = 0; i < len; i++) {
+               if (neighbors[i] == n)
+                       return false;
+       }
+       if (len == neighbors.length) {
+               Node[] temp = new Node[3 * neighbors.length / 2];
+               System.arraycopy(neighbors, 0, temp, 0, neighbors.length);
+               neighbors = temp;
+       }
+       neighbors[len] = n;
+       len++;
+       return true;
+}
+
+// --------------------------------------------------------------------------
+
+public Node getNeighbor(int i)
+{
+       return neighbors[i];
+}
+
+// --------------------------------------------------------------------------
+
+public int degree()
+{
+       return len;
+}
+
+// --------------------------------------------------------------------------
+
+public void pack()
+{
+       if (len == neighbors.length)
+               return;
+       Node[] temp = new Node[len];
+       System.arraycopy(neighbors, 0, temp, 0, len);
+       neighbors = temp;
+}
+
+// --------------------------------------------------------------------------
+
+public String toString()
+{
+       if( neighbors == null ) return "DEAD!";
+       StringBuffer buffer = new StringBuffer();
+       buffer.append("len=" + len + " maxlen=" + neighbors.length + " [");
+       for (int i = 0; i < len; ++i) {
+               buffer.append(neighbors[i].getIndex() + " ");
+       }
+       return buffer.append("]").toString();
+}
+
+// --------------------------------------------------------------------------
+
+public void onKill()
+{
+       neighbors = null;
+       len = 0;
+}
+
+}
diff --git a/contrib/psg/src/peersim/core/Linkable.java b/contrib/psg/src/peersim/core/Linkable.java
new file mode 100644 (file)
index 0000000..962b427
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.core;
+
+
+/**
+* Instances of classes implementing this interface can form networks (graphs)
+* in the simulator framework.
+* The interface is similar to one of a container (containing neighbors),
+* only the types of the contained elements have to be {@link Node}.
+* The neighbor collection is defined in a random access list style, but
+* it must follow the contract of a set too (elements must be unique).
+* <p>
+* Also note that there is no possibility to remove elements from the
+* neighbor set. This is because removal is usually costly and it does not make
+* sense in the context of our applications,
+* where this interface is used for 1) initialization and 2)
+* providing an interface for other protocols for accessing the neighbor list.
+* Protocols that manage links remove, refresh, etc their link set internally
+* or through custom methods.
+* Therefore it would only put an unnecessary burden on implementors.
+*/
+public interface Linkable extends Cleanable {
+
+       /**
+       * Returns the size of the neighbor list.
+       */
+       public int degree();
+
+       /**
+       * Returns the neighbor with the given index. The contract is that
+       * listing the elements from index 0 to index degree()-1 should list
+       * each element exactly once if this object is not modified in the
+       * meantime. It throws an IndexOutOfBounds exception if i is negative
+       * or larger than or equal to {@link #degree}.
+       */
+       public Node getNeighbor(int i);
+
+       /**
+       * Add a neighbor to the current set of neighbors. If neighbor
+       * is not yet a neighbor but it cannot be added from other reasons,
+       * this method should not return normally, that is, it must throw
+       * a runtime exception.
+       * @return true if the neighbor has been inserted; false if the 
+       *    node is already a neighbor of this node
+       */
+       public boolean addNeighbor(Node neighbour);
+
+       /**
+       * Returns true if the given node is a member of the neighbor set.
+       */
+       public boolean contains(Node neighbor);
+       
+       /**
+       * A possibility for optimization. An implementation should try to
+       * compress its internal representation. Normally this is called
+       * by initializers or other components when
+       * no increase in the expected size of the neighborhood can be
+       * expected.
+       */
+       public void pack();
+}
+
diff --git a/contrib/psg/src/peersim/core/MaliciousProtocol.java b/contrib/psg/src/peersim/core/MaliciousProtocol.java
new file mode 100644 (file)
index 0000000..26ed74f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+/**
+ * Tag interface to identify protocols that are malicious.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.2 $
+ */
+public interface MaliciousProtocol 
+extends Protocol 
+{
+}
+
diff --git a/contrib/psg/src/peersim/core/ModifiableNode.java b/contrib/psg/src/peersim/core/ModifiableNode.java
new file mode 100644 (file)
index 0000000..7ce80a3
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+
+/**
+ * This class extends GeneralNode by allowing to modify single
+ * protocol instances at nodes.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.3 $
+ */
+public class ModifiableNode extends GeneralNode
+{
+
+/**
+ * Invokes the super constructor.
+ */
+public ModifiableNode(String prefix)
+{
+       super(prefix);
+}
+
+/**
+ * Substitutes the specified protocol at this node.
+ * 
+ * @param pid protocol identifier
+ * @param prot the protocol object
+ */
+public void setProtocol(int pid, Protocol prot)
+{
+       protocol[pid] = prot;
+}
+
+}
diff --git a/contrib/psg/src/peersim/core/Network.java b/contrib/psg/src/peersim/core/Network.java
new file mode 100644 (file)
index 0000000..da9c545
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+import peersim.Simulator;
+import peersim.config.Configuration;
+import psgsim.PSGDynamicNetwork;
+
+import java.util.Comparator;
+import java.util.Arrays;
+
+import org.simgrid.msg.HostNotFoundException;
+import org.simgrid.msg.MsgException;
+
+/**
+ * This class forms the basic framework of all simulations. This is a static
+ * singleton which is based on the assumption that we will simulate only one
+ * overlay network at a time. This allows us to reduce memory usage in many
+ * cases by allowing all the components to directly reach the fields of this
+ * class without having to store a reference.
+ * <p>
+ * The network is a set of nodes implemented via an array list for the sake of
+ * efficiency. Each node has an array of protocols. The protocols within a node
+ * can interact directly as defined by their implementation, and can be imagined
+ * as processes running in a common local environment (i.e. the node). This
+ * class is called a "network" because, although it is only a set of nodes, in
+ * most simulations there is at least one {@link Linkable} protocol that defines
+ * connections between nodes. In fact, such a {@link Linkable} protocol layer
+ * can be accessed through a {@link peersim.graph.Graph} view using
+ * {@link OverlayGraph}.
+ */
+public class Network {
+
+       // ========================= fields =================================
+       // ==================================================================
+
+       /**
+        * This config property defines the node class to be used. If not set, then
+        * {@link GeneralNode} will be used.
+        * 
+        * @config
+        */
+       private static final String PAR_NODE = "network.node";
+
+       /**
+        * This config property defines the initial capacity of the overlay network.
+        * If not set then the value of {@value #PAR_SIZE} will be used. The main
+        * purpose of this parameter is that it allows for optimization. In the case
+        * of scenarios when the network needs to grow, setting this to the maximal
+        * expected size of the network avoids reallocation of memory during the
+        * growth of the network.
+        * 
+        * @see #getCapacity
+        * @config
+        */
+       private static final String PAR_MAXSIZE = "network.initialCapacity";
+
+       /**
+        * This config property defines the initial size of the overlay network.
+        * This property is required.
+        * 
+        * @config
+        */
+       private static final String PAR_SIZE = "network.size";
+
+       /**
+        * The node array. This is not a private array which is not nice but
+        * efficiency has the highest priority here. The main purpose is to allow
+        * the package quick reading of the contents in a maximally flexible way.
+        * Nevertheless, methods of this class should be used instead of the array
+        * when modifying the contents. Because this array is not private, it is
+        * necessary to know that the actual node set is only the first
+        * {@link #size()} items of the array.
+        */
+       static Node[] node = null;
+
+       /**
+        * Actual size of the network.
+        */
+       private static int len;
+
+       /**
+        * The prototype node which is used to populate the simulation via cloning.
+        * After all the nodes have been cloned, {@link Control} components can be
+        * applied to perform any further initialization.
+        */
+       public static Node prototype = null;
+
+       // ====================== initialization ===========================
+       // =================================================================
+
+       /**
+        * Reads configuration parameters, constructs the prototype node, and
+        * populates the network by cloning the prototype.
+        */
+       public static void reset() {
+
+               if (prototype != null) {
+                       // not first experiment
+                       while (len > 0)
+                               remove(); // this is to call onKill on all nodes
+                       prototype = null;
+                       node = null;
+               }
+
+               len = Configuration.getInt(PAR_SIZE);
+               int maxlen = Configuration.getInt(PAR_MAXSIZE, len);
+               if (maxlen < len)
+                       throw new IllegalArgumentException(PAR_MAXSIZE + " is less than "
+                                       + PAR_SIZE);
+
+               node = new Node[maxlen];
+
+               // creating prototype node
+               Node tmp = null;
+               if (!Configuration.contains(PAR_NODE)) {
+                       System.err.println("Network: no node defined, using GeneralNode");
+                       tmp = new GeneralNode("");
+               } else {
+                       tmp = (Node) Configuration.getInstance(PAR_NODE);
+               }
+               prototype = tmp;
+               prototype.setIndex(-1);
+
+               // cloning the nodes
+               if (len > 0) {
+                       for (int i = 0; i < len; ++i) {
+                               node[i] = (Node) prototype.clone();
+                               node[i].setIndex(i);
+                       }
+               }
+       }
+
+       /** Disable instance construction */
+       private Network() {
+       }
+
+       // =============== public methods ===================================
+       // ==================================================================
+
+       /** Number of nodes currently in the network */
+       public static int size() {
+               return len;
+       }
+
+       // ------------------------------------------------------------------
+
+       /**
+        * Sets the capacity of the internal array storing the nodes. The nodes will
+        * remain the same in the same order. If the new capacity is less than the
+        * old size of the node list, than the end of the list is cut. The nodes
+        * that get removed via this cutting are removed through {@link #remove()}.
+        */
+       public static void setCapacity(int newSize) {
+
+               if (node == null || newSize != node.length) {
+                       for (int i = newSize; i < len; ++i)
+                               remove();
+                       Node[] newnodes = new Node[newSize];
+                       final int l = Math.min(node.length, newSize);
+                       System.arraycopy(node, 0, newnodes, 0, l);
+                       node = newnodes;
+                       if (len > newSize)
+                               len = newSize;
+               }
+       }
+
+       // ------------------------------------------------------------------
+
+       /**
+        * Returns the maximal number of nodes that can be stored without
+        * reallocating the underlying array to increase capacity.
+        */
+       public static int getCapacity() {
+               return node.length;
+       }
+
+       // ------------------------------------------------------------------
+
+       /**
+        * The node will be appended to the end of the list. If necessary, the
+        * capacity of the internal array is increased.
+        */
+       public static void add(Node n) {
+               if (len == node.length)
+                       setCapacity(3 * node.length / 2 + 1);
+               node[len] = n;
+               n.setIndex(len);
+               len++;
+               if (Simulator.getSimID() == 2)
+                       try {
+                               PSGDynamicNetwork.add(n);
+                       } catch (HostNotFoundException e) {
+                               System.err.println("Host not found in platform file");
+                       }
+               System.err.println("node " + n.getID() + " with index " + n.getIndex()
+                               + " was added at time " + CommonState.getTime());
+       }
+
+       // ------------------------------------------------------------------
+
+       /**
+        * Returns node with the given index. Note that the same node will normally
+        * have a different index in different times. This can be used as a random
+        * access iterator. This method does not perform range checks to increase
+        * efficiency. The maximal valid index is {@link #size()}.
+        */
+       public static Node get(int index) {
+               return node[index];
+       }
+
+       // ------------------------------------------------------------------
+
+       /**
+        * The node at the end of the list is removed. Returns the removed node. It
+        * also sets the fail state of the node to {@link Fallible#DEAD}.
+        */
+       public static Node remove() {
+               Node n = node[len - 1]; // if len was zero this throws and exception
+               node[len - 1] = null;
+               len--;
+               System.err.println("node " + n.getID() + " with index " + n.getIndex()
+                               + " was removed at time " + CommonState.getTime());
+               n.setFailState(Fallible.DEAD);
+               if (Simulator.getSimID() == 2)
+                       PSGDynamicNetwork.remove(n);
+               return n;
+       }
+
+       // ------------------------------------------------------------------
+
+       /**
+        * The node with the given index is removed. Returns the removed node. It
+        * also sets the fail state of the node to {@link Fallible#DEAD}.
+        * <p>
+        * Look out: the index of the other nodes will not change (the right hand
+        * side of the list is not shifted to the left) except that of the last
+        * node. Only the last node is moved to the given position and will get
+        * index i.
+        */
+       public static Node remove(int i) {
+
+               if (i < 0 || i >= len)
+                       throw new IndexOutOfBoundsException("" + i);
+               swap(i, len - 1);
+               return remove();
+       }
+
+       // ------------------------------------------------------------------
+
+       /**
+        * Swaps the two nodes at the given indexes.
+        */
+       public static void swap(int i, int j) {
+
+               Node n = node[i];
+               node[i] = node[j];
+               node[j] = n;
+               node[j].setIndex(j);
+               node[i].setIndex(i);
+       }
+
+       // ------------------------------------------------------------------
+
+       /**
+        * Shuffles the node array. The index of each node is updated accordingly.
+        */
+       public static void shuffle() {
+
+               for (int i = len; i > 1; i--)
+                       swap(i - 1, CommonState.r.nextInt(i));
+
+       }
+
+       // ------------------------------------------------------------------
+
+       /**
+        * Sorts the node array. The index of each node is updated accordingly.
+        * 
+        * @param c
+        *            The comparator to be used for sorting the nodes. If null, the
+        *            natural order of the nodes is used.
+        */
+       public static void sort(Comparator<? super Node> c) {
+
+               Arrays.sort(node, 0, len, c);
+               for (int i = 0; i < len; i++)
+                       node[i].setIndex(i);
+       }
+
+       // ------------------------------------------------------------------
+
+       public static void test() {
+
+               System.err.println("number of nodes = " + len);
+               System.err.println("capacity (max number of nodes) = " + node.length);
+               for (int i = 0; i < len; ++i) {
+                       System.err.println("node[" + i + "]");
+                       System.err.println(node[i].toString());
+               }
+
+               if (prototype == null)
+                       return;
+               for (int i = 0; i < prototype.protocolSize(); ++i) {
+                       if (prototype.getProtocol(i) instanceof Linkable)
+                               peersim.graph.GraphIO.writeUCINET_DL(new OverlayGraph(i),
+                                               System.err);
+               }
+       }
+
+}
diff --git a/contrib/psg/src/peersim/core/Node.java b/contrib/psg/src/peersim/core/Node.java
new file mode 100644 (file)
index 0000000..a64e3a2
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+/**
+ * Class that represents one node with a network address. An {@link Network} is
+ * made of a set of nodes. The functionality of this class is thin: it must be
+ * able to represent failure states and store a list of protocols. It is the
+ * protocols that do the interesting job.
+ */
+public interface Node extends Fallible, Cloneable
+{
+
+/**
+ * Prefix of the parameters that defines protocols.
+ * @config
+ */
+public static final String PAR_PROT = "protocol";
+
+/**
+ * Returns the <code>i</code>-th protocol in this node. If <code>i</code> 
+ * is not a valid protocol id
+ * (negative or larger than or equal to the number of protocols), then it throws
+ * IndexOutOfBoundsException.
+ */
+public Protocol getProtocol(int i);
+
+/**
+ * Returns the number of protocols included in this node.
+ */
+public int protocolSize();
+
+/**
+ * Sets the index of this node in the internal representation of the node list.
+ * Applications should not use this method. It is defined as public simply
+ * because it is not possible to define it otherwise.
+ * Using this method will result in
+ * undefined behavior. It is provided for the core system.
+ */
+public void setIndex(int index);
+
+/**
+ * Returns the index of this node. It is such that
+ * <code>Network.get(n.getIndex())</code> returns n. This index can
+ * change during a simulation, it is not a fixed id. If you need that, use
+ * {@link #getID}.
+ * @see Network#get
+ */
+public int getIndex();
+
+/**
+* Returns the unique ID of the node. It is guaranteed that the ID is unique
+* during the entire simulation, that is, there will be no different Node
+* objects with the same ID in the system during one invocation of the JVM.
+* Preferably nodes
+* should implement <code>hashCode()</code> based on this ID. 
+*/
+public long getID();
+
+/**
+ * Clones the node. It is defined as part of the interface
+ * to change the access right to public and to get rid of the
+ * <code>throws</code> clause. 
+ */
+public Object clone();
+
+}
diff --git a/contrib/psg/src/peersim/core/OracleIdleProtocol.java b/contrib/psg/src/peersim/core/OracleIdleProtocol.java
new file mode 100644 (file)
index 0000000..4d1896f
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.core;
+
+/**
+* A protocol that does nothing but knows everything.
+* It provides an interface which models a protocol that knows all nodes
+* in the network, i.e. the neighborhood set of this protocol is always the
+* whole node set. this protocol is also extremely cheap, in fact it
+* has no data fields.
+*/
+public final class OracleIdleProtocol implements Protocol, Linkable {
+
+// =================== initialization, creation ======================
+// ===================================================================
+
+
+/** Does nothing */
+public OracleIdleProtocol(String prefix) {}
+
+// --------------------------------------------------------------------
+
+/** Returns <tt>this</tt> to maximize memory saving. It contains no fields.*/
+public Object clone() { return this; }
+
+
+// ===================== public methods ===============================
+// ====================================================================
+
+
+/** This is an expensive operation, should not be used at all.
+* It returns false only if the given node is not in the current network.
+*/
+public boolean contains(Node n) {
+
+       final int len = Network.size();
+       for (int i=0; i < len; i++)
+       {
+               if (Network.node[i] == n)
+               return true;
+       }
+       return false;
+}
+
+// --------------------------------------------------------------------
+
+/** Unsupported operation */
+public boolean addNeighbor(Node n) {
+
+       throw new UnsupportedOperationException();
+}
+
+// --------------------------------------------------------------------
+  
+/**
+* The neighborhood contains the node itself, ie it contains the loop
+* edge.
+*/
+public Node getNeighbor(int i) {
+       
+       return Network.node[i];
+}
+
+// --------------------------------------------------------------------
+
+public int degree() {
+       
+       return Network.size();
+}
+
+// --------------------------------------------------------------------
+
+public void pack() {}  
+
+// --------------------------------------------------------------------
+
+public void onKill() {}
+
+// --------------------------------------------------------------------
+
+public String toString() {
+
+       return degree()+" [all the nodes of the overlay network]";
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/core/OverlayGraph.java b/contrib/psg/src/peersim/core/OverlayGraph.java
new file mode 100644 (file)
index 0000000..0009459
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.core;
+
+import peersim.graph.Graph;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+* This class is an adaptor which makes a {@link Linkable} protocol layer
+* look like a graph. It is useful because it allows the application of many
+* graph algorithms and graph topology initialization methods.
+* If the overlay network changes after creating this object, the changes
+* will be reflected. However, if the nodes are reshuffled (see
+* {@link Network#shuffle}), or if the node list changes (addition/removal),
+* then the behaviour becomes unspecified.
+*
+* The indices of nodes are from 0 to Network.size()-1.
+*
+* The fail state of nodes has an effect on the graph: all nodes are included
+* but edges are included only if both ends are up. This expresses the fact
+* that this graph is in fact defined by the "can communicate with" relation.
+*/
+public class OverlayGraph implements Graph {
+
+
+// ====================== fields ================================
+// ==============================================================
+
+/**
+* The protocol ID that selects the Linkable protocol to convert to a graph.
+*/
+public final int protocolID;
+
+/**
+* Tells if the graph should be wired in an undirected way.
+* Method {@link #directed} returns true always, this affects only
+* method {@link #setEdge}: if false, then the opposite edge is set too.
+*/
+public final boolean wireDirected;
+
+// ====================== public constructors ===================
+// ==============================================================
+
+/**
+* @param protocolID The protocol on which this adaptor is supposed
+* to operate.
+*/
+public OverlayGraph( int protocolID ) {
+
+       this.protocolID = protocolID;
+       wireDirected = true;
+}
+
+// --------------------------------------------------------------
+
+/**
+* @param protocolID The protocol on which this adaptor is supposed
+* to operate.
+* @param wireDirected specifies if {@link #setEdge} would wire the
+* opposite edge too.
+*/
+public OverlayGraph( int protocolID, boolean wireDirected ) {
+
+       this.protocolID = protocolID;
+       this.wireDirected = wireDirected;
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+       
+       return
+               ((Linkable)Network.node[i].getProtocol(protocolID)
+               ).contains(Network.node[j]) &&
+               Network.node[j].isUp() &&
+               Network.node[i].isUp();
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Returns those neighbors that are up. If node i is not up, it returns
+* an empty list.
+*/
+public Collection<Integer> getNeighbours(int i) {
+       
+       Linkable lble=(Linkable)Network.node[i].getProtocol(protocolID);
+       ArrayList<Integer> al = new ArrayList<Integer>(lble.degree());
+       if( Network.node[i].isUp() )
+       {       
+               for(int j=0; j<lble.degree(); ++j)
+               {
+                       final Node n = lble.getNeighbor(j);
+                       // if accessible, we include it
+                       if(n.isUp()) al.add(Integer.valueOf(n.getIndex()));
+               }
+       }
+       return Collections.unmodifiableList(al);
+}
+
+// ---------------------------------------------------------------
+
+/** Returns <code>Network.node[i]</code> */
+public Object getNode(int i) { return Network.node[i]; }
+       
+// ---------------------------------------------------------------
+
+/**
+* Returns null always
+*/
+public Object getEdge(int i, int j) { return null; }
+
+// ---------------------------------------------------------------
+
+/** Returns <code>Network.size()</code> */
+public int size() { return Network.size(); }
+
+// --------------------------------------------------------------------
+       
+/** Returns always true */
+public boolean directed() { return true; }
+
+// --------------------------------------------------------------------
+
+/**
+* Sets given edge.
+* In some cases this behaves strangely. Namely, when node i or j is not up,
+* but is not dead (e.g. it can be down temporarily).
+* In such situations the relevant link is made, but afterwards
+* getEdge(i,j) will NOT return true, only when the fail state has changed back
+* to OK.
+*
+* <p>Conceptually one can think of it as a successful operation which is
+* immediately overruled by the dynamics of the underlying overlay network.
+* Let's not forget that this class is an adaptor only.
+*
+* <p>
+* The behaviour of this method is affected by parameter {@link #wireDirected}.
+* If it is false, then the opposite edge is set too.
+*/
+public boolean setEdge( int i, int j ) {
+// XXX slightly unintuitive behavior but makes sense when understood
+       
+       if( !wireDirected ) 
+               ((Linkable)Network.node[j].getProtocol(protocolID)
+               ).addNeighbor(Network.node[i]);
+
+
+       return
+               ((Linkable)Network.node[i].getProtocol(protocolID)
+               ).addNeighbor(Network.node[j]);
+}
+
+// ---------------------------------------------------------------
+
+/** Not supported */
+public boolean clearEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Returns number of neighbors that are up. If node i is down, returns 0.
+*/
+public int degree(int i) {
+
+       if( !Network.node[i].isUp() ) return 0;
+       Linkable lble=(Linkable)Network.node[i].getProtocol(protocolID);
+       int numNeighbours = 0;
+       for(int j=0; j<lble.degree(); ++j)
+       {
+               final Node n = lble.getNeighbor(j);
+               // if accessible, we count it
+               if(n.isUp()) numNeighbours++;
+       }
+       return numNeighbours;
+}
+
+
+// ========================= other methods =======================
+// ===============================================================
+
+
+/**
+* Returns number of neighbors that are either up or down.
+* If node i is down, returns 0.
+*/
+public int fullDegree(int i) {
+
+       if( !Network.node[i].isUp() ) return 0;
+       Linkable lble=(Linkable)Network.node[i].getProtocol(protocolID);
+       return lble.degree();
+}
+
+
+}
+
+
diff --git a/contrib/psg/src/peersim/core/Protocol.java b/contrib/psg/src/peersim/core/Protocol.java
new file mode 100644 (file)
index 0000000..04e8ecf
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+/**
+ * Interface to identify protocols.
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.5 $
+ */
+public interface Protocol extends Cloneable
+{
+
+/**
+ * Returns a clone of the protocol. It is important to pay attention to
+ * implement this carefully because in peersim all nodes are generated by
+ * cloning except a prototype node. That is, the constructor of protocols is
+ * used only to construct the prototype. Initialization can be done
+ * via {@link Control}s.
+ */
+public Object clone();
+
+}
diff --git a/contrib/psg/src/peersim/core/Scheduler.java b/contrib/psg/src/peersim/core/Scheduler.java
new file mode 100644 (file)
index 0000000..035f982
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.core;
+
+import peersim.config.*;
+
+// XXX a quite primitive scheduler, should be able to be configured
+// much more flexibly using a simple syntax for time ranges.
+/**
+* A binary function over the time points. That is,
+* for each time point returns a boolean value.
+* 
+* The concept of time depends on the simulation model. Current time
+* has to be set by the simulation engine, irrespective of the model,
+* and can be read using {@link CommonState#getTime()}. This scheduler
+* is interpreted over those time points.
+*
+* <p>In this simple implementation the valid times will be
+* <tt>from, from+step, from+2*step, etc,</tt>
+* where the last element is strictly less than <tt>until</tt>.
+* Alternatively, if <tt>at</tt> is defined, then the schedule will be a single
+* time point. If FINAL is
+* defined, it is also added to the set of active time points.
+* It refers to the time after the simulation has finished (see
+* {@link CommonState#getPhase}).
+*/
+public class Scheduler {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+
+/**
+* Defaults to 1.
+* @config
+*/
+private static final String PAR_STEP = "step";
+
+/** 
+* Defaults to -1. That is, defaults to be ineffective.
+* @config
+*/
+private static final String PAR_AT = "at";
+
+
+/** 
+* Defaults to 0.
+* @config
+*/
+private static final String PAR_FROM = "from";
+
+/** 
+* Defaults to <tt>Long.MAX_VALUE</tt>.
+* @config
+*/
+private static final String PAR_UNTIL = "until";
+
+/**
+* Defines if component is active after the simulation has finished.
+* Note that the exact time the simulation finishes is not know in advance
+* because other components can stop the simulation at any time.
+* By default not set.
+* @see CommonState#getPhase
+* @config
+*/
+private static final String PAR_FINAL = "FINAL";
+
+public final long step;
+
+public final long from;
+
+public final long until;
+
+public final boolean fin;
+
+/** The next scheduled time point.*/
+protected long next = -1;
+
+// ==================== initialization ==============================
+// ==================================================================
+
+
+/** Reads configuration parameters from the component defined by
+* <code>prefix</code>. {@value #PAR_STEP} defaults to 1.
+*/
+public Scheduler(String prefix) {
+       
+       this(prefix, true);
+}
+
+// ------------------------------------------------------------------
+
+/** Reads configuration parameters from the component defined by
+* <code>prefix</code>. If useDefault is false, then at least parameter
+* {@value #PAR_STEP} must be explicitly defined. Otherwise {@value #PAR_STEP}
+* defaults to 1.
+*/
+public Scheduler(String prefix, boolean useDefault)
+{
+       if (Configuration.contains(prefix+"."+PAR_AT)) {
+               // FROM, UNTIL, and STEP should *not* be defined
+               if (Configuration.contains(prefix+"."+PAR_FROM) ||
+                               Configuration.contains(prefix+"."+PAR_UNTIL) ||
+                               Configuration.contains(prefix+"."+PAR_STEP))
+                       throw new IllegalParameterException(prefix,
+                               "Cannot use \""+PAR_AT+"\" together with \""
+                               +PAR_FROM+"\", \""+PAR_UNTIL+"\", or \""+
+                               PAR_STEP+"\"");
+
+               from = Configuration.getLong(prefix+"."+PAR_AT);
+               until = from+1;
+               step = 1;
+       } else {
+               if (useDefault) 
+                       step = Configuration.getLong(prefix+"."+PAR_STEP,1);
+               else
+                       step = Configuration.getLong(prefix+"."+PAR_STEP);
+               if( step < 1 )
+                       throw new IllegalParameterException(prefix,
+                               "\""+PAR_STEP+"\" must be >= 1");
+               
+               from = Configuration.getLong(prefix+"."+PAR_FROM,0);
+               until = Configuration.getLong(prefix+"."+PAR_UNTIL,Long.MAX_VALUE);
+       }
+
+       if( from < until ) next = from;
+       else next = -1;
+       
+       fin = Configuration.contains(prefix+"."+PAR_FINAL);
+}
+
+
+// ===================== public methods ==============================
+// ===================================================================
+
+/** true if given time point is covered by this scheduler */
+public boolean active(long time) {
+       
+       if( time < from || time >= until ) return false;
+       return (time - from)%step == 0; 
+}
+
+// -------------------------------------------------------------------
+
+/** true if current time point is covered by this scheduler */
+public boolean active() {
+       
+       return active( CommonState.getTime() );
+}
+
+//-------------------------------------------------------------------
+
+/**
+* Returns the next time point. If the returned value is negative, there are
+* no more time points. As a side effect, it also updates the next time point,
+* so repeated calls to this method return the scheduled times.
+*/
+public long getNext()
+{
+       long ret = next;
+       // check like this to prevent integer overflow of "next"
+       if( until-next > step ) next += step;
+       else next = -1;
+       return ret;
+}
+
+}
+
+
diff --git a/contrib/psg/src/peersim/dynamics/DynamicNetwork.java b/contrib/psg/src/peersim/dynamics/DynamicNetwork.java
new file mode 100644 (file)
index 0000000..a581a86
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import java.util.Map;
+
+import org.simgrid.msg.Host;
+import org.simgrid.msg.MsgException;
+
+import peersim.Simulator;
+import peersim.config.Configuration;
+import peersim.core.*;
+import psgsim.NodeHost;
+import psgsim.PSGDynamicNetwork;
+
+/**
+ * This {@link Control} can change the size of networks by adding and removing
+ * nodes. Can be used to model churn. This class supports only permanent removal
+ * of nodes and the addition of brand new nodes. That is, temporary downtime is
+ * not supported by this class.
+ */
+public class DynamicNetwork implements Control {
+
+       // --------------------------------------------------------------------------
+       // Parameters
+       // --------------------------------------------------------------------------
+
+       /**
+        * Config parameter which gives the prefix of node initializers. An
+        * arbitrary number of node initializers can be specified (Along with their
+        * parameters). These will be applied on the newly created nodes. The
+        * initializers are ordered according to alphabetical order if their ID.
+        * Example:
+        * 
+        * <pre>
+        * control.0 DynamicNetwork
+        * control.0.init.0 RandNI
+        * control.0.init.0.k 5
+        * control.0.init.0.protocol somelinkable
+        * ...
+        * </pre>
+        * 
+        * @config
+        */
+       private static final String PAR_INIT = "init";
+
+       /**
+        * If defined, nodes are substituted (an existing node is removed, a new one
+        * is added. That is, first the number of nodes to add (or remove if
+        * {@value #PAR_ADD} is negative) is calculated, and then exactly the same
+        * number of nodes are removed (or added) immediately so that the network
+        * size remains constant. Not set by default.
+        * 
+        * @config
+        */
+       private static final String PAR_SUBST = "substitute";
+
+       /**
+        * Specifies the number of nodes to add or remove. It can be negative in
+        * which case nodes are removed. If its absolute value is less than one,
+        * then it is interpreted as a proportion of current network size, that is,
+        * its value is substituted with <tt>add*networksize</tt>. Its value is
+        * rounded to an integer.
+        * 
+        * @config
+        */
+       private static final String PAR_ADD = "add";
+
+       /**
+        * Nodes are added until the size specified by this parameter is reached.
+        * The network will never exceed this size as a result of this class. If not
+        * set, there will be no limit on the size of the network.
+        * 
+        * @config
+        */
+       private static final String PAR_MAX = "maxsize";
+
+       /**
+        * Nodes are removed until the size specified by this parameter is reached.
+        * The network will never go below this size as a result of this class.
+        * Defaults to 0.
+        * 
+        * @config
+        */
+       private static final String PAR_MIN = "minsize";
+
+       // --------------------------------------------------------------------------
+       // Fields
+       // --------------------------------------------------------------------------
+
+       /** value of {@value #PAR_ADD} */
+       protected final double add;
+
+       /** value of {@value #PAR_SUBST} */
+       protected final boolean substitute;
+
+       /** value of {@value #PAR_MIN} */
+       protected final int minsize;
+
+       /** value of {@value #PAR_MAX} */
+       protected final int maxsize;
+
+       /** node initializers to apply on the newly added nodes */
+       protected final NodeInitializer[] inits;
+
+       // --------------------------------------------------------------------------
+       // Protected methods
+       // --------------------------------------------------------------------------
+
+       /**
+        * Adds n nodes to the network. Extending classes can implement any
+        * algorithm to do that. The default algorithm adds the given number of
+        * nodes after calling all the configured initializers on them.
+        * 
+        * @param n
+        *            the number of nodes to add, must be non-negative.
+        */
+       protected void add(int n) {
+               for (int i = 0; i < n; ++i) {
+                       Node newnode = (Node) Network.prototype.clone();
+                       for (int j = 0; j < inits.length; ++j) {
+                               inits[j].initialize(newnode);
+                       }
+                       Network.add(newnode);
+
+               }
+       }
+
+       // ------------------------------------------------------------------
+
+       /**
+        * Removes n nodes from the network. Extending classes can implement any
+        * algorithm to do that. The default algorithm removes <em>random</em> nodes
+        * <em>permanently</em> simply by calling {@link Network#remove(int)}.
+        * 
+        * @param n
+        *            the number of nodes to remove
+        */
+       protected void remove(int n) {
+               for (int i = 0; i < n; ++i) {
+                       int nr = CommonState.r.nextInt(Network.size());
+                       Network.remove(nr);
+
+               }
+       }
+
+       // --------------------------------------------------------------------------
+       // Initialization
+       // --------------------------------------------------------------------------
+
+       /**
+        * Standard constructor that reads the configuration parameters. Invoked by
+        * the simulation engine.
+        * 
+        * @param prefix
+        *            the configuration prefix for this class
+        */
+       public DynamicNetwork(String prefix) {
+               add = Configuration.getDouble(prefix + "." + PAR_ADD);
+               substitute = Configuration.contains(prefix + "." + PAR_SUBST);
+               Object[] tmp = Configuration.getInstanceArray(prefix + "." + PAR_INIT);
+               inits = new NodeInitializer[tmp.length];
+               for (int i = 0; i < tmp.length; ++i) {
+                       // System.out.println("Inits " + tmp[i]);
+                       inits[i] = (NodeInitializer) tmp[i];
+               }
+               maxsize = Configuration.getInt(prefix + "." + PAR_MAX,
+                               Integer.MAX_VALUE);
+               minsize = Configuration.getInt(prefix + "." + PAR_MIN, 0);
+       }
+
+       // --------------------------------------------------------------------------
+       // Public methods
+       // --------------------------------------------------------------------------
+
+       /**
+        * Calls {@link #add(int)} or {@link #remove} with the parameters defined by
+        * the configuration.
+        * 
+        * @return always false
+        */
+       public final boolean execute() {
+               if (add == 0)
+                       return false;
+               if (!substitute) {
+                       if ((maxsize <= Network.size() && add > 0)
+                                       || (minsize >= Network.size() && add < 0))
+                               return false;
+               }
+               int toadd = 0;
+               int toremove = 0;
+               if (add > 0) {
+                       toadd = (int) Math.round(add < 1 ? add * Network.size() : add);
+                       if (!substitute && toadd > maxsize - Network.size())
+                               toadd = maxsize - Network.size();
+                       if (substitute)
+                               toremove = toadd;
+               } else if (add < 0) {
+                       toremove = (int) Math
+                                       .round(add > -1 ? -add * Network.size() : -add);
+                       if (!substitute && toremove > Network.size() - minsize)
+                               toremove = Network.size() - minsize;
+                       if (substitute)
+                               toadd = toremove;
+               }
+               remove(toremove);
+               add(toadd);
+               return false;
+       }
+
+       // --------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/MethodInvoker.java b/contrib/psg/src/peersim/dynamics/MethodInvoker.java
new file mode 100644 (file)
index 0000000..5e9e5fc
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import java.lang.reflect.*;
+import peersim.config.*;
+import peersim.core.*;
+import java.util.ArrayList;
+
+/**
+ * This {@link Control} invokes a specified method on a protocol.
+ * The method is defined by config parameter {@value #PAR_METHOD} and
+ * the protocol is by {@value #PAR_PROT}. The method must not have any
+ * parameters and must return void. If no protocol is specified, then the
+ * method will be invoked on all protocol in the protocol stack that define
+ * it.
+ * <p>
+ * Although the method cannot have any parameters, it can of course read
+ * {@link CommonState}. It is guaranteed that the state is up-to-date,
+ * inlcuding eg method {@link CommonState#getNode}.
+ */
+public class MethodInvoker implements Control, NodeInitializer {
+
+
+// --------------------------------------------------------------------------
+// Parameter names
+// --------------------------------------------------------------------------
+
+/**
+ * The protocol to operate on.
+ * If not defined, the given method will be invoked on all protocols that
+ * define it. In all cases, at least one protocol has to define it.
+ * @config
+ */
+private static final String PAR_PROT = "protocol";
+
+/**
+ * The method to be invoked. It must return void and should not have any
+ * parameters specified.
+ * @config
+ */
+private static final String PAR_METHOD = "method";
+
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Identifiers of the protocols to be initialized */
+private final int pid[];
+
+/** Method name */
+private final String methodName;
+
+/** Methods corresponding to the protocols in {@link #pid}. */
+private final Method method[];
+
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public MethodInvoker(String prefix) {
+
+       methodName = Configuration.getString(prefix+"."+PAR_METHOD);
+       if(!Configuration.contains(prefix+"."+PAR_PROT))
+       {
+               // find protocols that implement method
+               ArrayList<Integer> pids = new ArrayList<Integer>();
+               ArrayList<Method> methods = new ArrayList<Method>();
+               for(int i=0; i<Network.prototype.protocolSize(); ++i)
+               {
+                       Method m = null;
+                       try
+                       {
+                               m = MethodInvoker.getMethod(
+                                 Network.prototype.getProtocol(i).getClass(),
+                                 methodName );
+                       }
+                       catch(NoSuchMethodException e) {}
+                       
+                       if(m!=null)
+                       {
+                               pids.add(i);
+                               methods.add(m);
+                       }
+               }
+
+               if( pids.isEmpty() )
+               {
+                       throw new IllegalParameterException(prefix + "." +
+                       PAR_METHOD,
+                       "No protocols found that implement 'void "+
+                       methodName+"()'");
+               }
+
+               pid=new int[pids.size()];
+               int j=0;
+               for(int i: pids) pid[j++]=i;
+               method=methods.toArray(new Method[methods.size()]);
+       }
+       else
+       {
+               pid = new int[1];
+               pid[0] = Configuration.getPid(prefix+"."+PAR_PROT);
+               try
+               {
+                       method = new Method[1];
+                       method[0]=MethodInvoker.getMethod(
+                         Network.prototype.getProtocol(pid[0]).getClass(),
+                         methodName );
+               }
+               catch (NoSuchMethodException e)
+               {
+                       throw new IllegalParameterException(prefix + "." +
+                       PAR_METHOD, e+"");
+               }
+       }
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+private static Method getMethod(Class cl, String methodName)
+throws NoSuchMethodException {
+
+       Method[] methods = cl.getMethods();
+       ArrayList<Method> list = new ArrayList<Method>();
+       for(Method m: methods)
+       {
+               if(m.getName().equals(methodName))
+               {
+                       Class[] pars = m.getParameterTypes();
+                       Class ret = m.getReturnType();
+                       if( pars.length == 0 && ret==void.class )
+                               list.add(m);
+               }
+       }
+       
+       if(list.size() == 0)
+       {
+               throw new NoSuchMethodException("Method "
+               + methodName + " in class " + cl.getName());
+       }
+       
+       return list.get(0);
+}
+
+//--------------------------------------------------------------------------
+
+/** Invokes method on all the nodes. */
+public boolean execute() {
+
+       for(int i=0; i<Network.size(); ++i)
+       {
+               initialize(Network.get(i));
+       }
+
+       return false;
+}
+
+//--------------------------------------------------------------------------
+
+/** Invokes method on given node. */
+public void initialize(Node n) {
+       
+       try
+       {
+               for(int i=0; i<pid.length; ++i)
+               {
+                       CommonState.setNode(n);
+                       CommonState.setPid(pid[i]);
+                       method[i].invoke(n.getProtocol(pid[i]));
+               }
+       }
+       catch(Exception e)
+       {
+               e.printStackTrace();
+               System.exit(1);
+       }
+}
+}
diff --git a/contrib/psg/src/peersim/dynamics/NodeInitializer.java b/contrib/psg/src/peersim/dynamics/NodeInitializer.java
new file mode 100644 (file)
index 0000000..7049a11
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import peersim.core.Node;
+
+/**
+ * Generic interface to initialize a node before inserting it into the
+ * simulation. Other components like {@link DynamicNetwork} can use a
+ * NodeInitializer. It is designed to allow maximal flexibility therefore poses
+ * virtually no restrictions on the implementation. It can even be used to
+ * implement initializations that require global knowledge of the system.
+ */
+public interface NodeInitializer
+{
+
+/**
+ * Performs arbitrary initializations on the given node. It is guaranteed that
+ * this is called <em>before</em> inserting the node into the network.
+ */
+public void initialize(Node n);
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/OscillatingNetwork.java b/contrib/psg/src/peersim/dynamics/OscillatingNetwork.java
new file mode 100644 (file)
index 0000000..4c10f2d
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+       
+package peersim.dynamics;
+
+import peersim.config.Configuration;
+import peersim.core.*;
+
+/**
+ * Makes the network size oscillate.
+ * The network size will be the function of time, parameterized by this
+ * parameter. The size function is
+ * <code>avg+sin(time*pi/{@value #PAR_PERIOD})*ampl</code> where
+ * <code>avg=({@value #PAR_MAX}+{@value #PAR_MIN})/2</code> and 
+ * <code>ampl=({@value #PAR_MAX}-{@value #PAR_MIN})/2</code>.
+ * This function is independent of how many times this class is executed, that
+ * is, whenever it is executed, it takes the current time and sets the network
+ * size accordingly.
+ */
+public class OscillatingNetwork implements Control
+{
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * Config parameter which gives the prefix of node initializers. An arbitrary
+ * number of node initializers can be specified (Along with their parameters).
+ * These will be applied
+ * on the newly created nodes. The initializers are ordered according to
+ * alphabetical order if their ID.
+ * Example:
+ * <pre>
+control.0 DynamicNetwork
+control.0.init.0 RandNI
+control.0.init.0.k 5
+control.0.init.0.protocol somelinkable
+...
+ * </pre>
+ * @config
+ */
+private static final String PAR_INIT = "init";
+
+/**
+ * Nodes are added until the size specified by this parameter is reached. The
+ * network will never exceed this size as a result of this class.
+ * If not set, there will be no limit on the size of the network.
+ * @config
+ */
+private static final String PAR_MAX = "maxsize";
+
+/**
+ * Nodes are removed until the size specified by this parameter is reached. The
+ * network will never go below this size as a result of this class.
+ * Defaults to 0.
+ * @config
+ */
+private static final String PAR_MIN = "minsize";
+
+/**
+ * Config parameter used to define the length of one period of the oscillation.
+ * The network size will be the function of time, parameterized by this
+ * parameter. The size function is
+ * <code>avg+sin(time*pi/{@value #PAR_PERIOD})*ampl</code> where
+ * <code>avg=({@value #PAR_MAX}+{@value #PAR_MIN})/2</code> and 
+ * <code>ampl=({@value #PAR_MAX}-{@value #PAR_MIN})/2</code>.
+ * @config
+ */
+private static final String PAR_PERIOD = "period";
+
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/** Period */
+private final int period;
+
+/** Maximum size */
+private final int minsize;
+
+/** Minimum size */
+private final int maxsize;
+
+/** New nodes initializers */
+private final NodeInitializer[] inits;
+
+
+//--------------------------------------------------------------------------
+// Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters. Invoked by the
+ * simulation engine.
+ * @param prefix
+ *          the configuration prefix for this class
+ */
+public OscillatingNetwork(String prefix)
+{
+
+       period = Configuration.getInt(prefix + "." + PAR_PERIOD);
+       maxsize =
+               Configuration.getInt(
+                       prefix + "." + PAR_MAX,
+                       Integer.MAX_VALUE);
+       minsize = Configuration.getInt(prefix + "." + PAR_MIN, 0);
+
+       Object[] tmp = Configuration.getInstanceArray(prefix + "." + PAR_INIT);
+       inits = new NodeInitializer[tmp.length];
+       for (int i = 0; i < tmp.length; ++i)
+       {
+               inits[i] = (NodeInitializer) tmp[i];
+       }
+}
+
+//--------------------------------------------------------------------------
+// Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Adds n nodes to the network. Extending classes can implement any algorithm to
+ * do that. The default algorithm adds the given number of nodes after calling
+ * all the configured initializers on them.
+ * 
+ * @param n
+ *          the number of nodes to add, must be non-negative.
+ */
+protected void add(int n)
+{
+       for (int i = 0; i < n; ++i) {
+               Node newnode = (Node) Network.prototype.clone();
+               for (int j = 0; j < inits.length; ++j) {
+                       inits[j].initialize(newnode);
+               }
+               Network.add(newnode);
+       }
+}
+
+// ------------------------------------------------------------------
+
+/**
+ * Removes n nodes from the network. Extending classes can implement any
+ * algorithm to do that. The default algorithm removes <em>random</em>
+ * nodes <em>permanently</em> simply by calling {@link Network#remove(int)}.
+ * @param n the number of nodes to remove
+ */
+protected void remove(int n)
+{
+       for (int i = 0; i < n; ++i) {
+               Network.remove(CommonState.r.nextInt(Network.size()));
+       }
+}
+
+// ------------------------------------------------------------------
+
+/**
+ * Takes the current time and sets the network size according to a periodic
+ * function of time.
+ * The size function is
+ * <code>avg+sin(time*pi/{@value #PAR_PERIOD})*ampl</code> where
+ * <code>avg=({@value #PAR_MAX}+{@value #PAR_MIN})/2</code> and 
+ * <code>ampl=({@value #PAR_MAX}-{@value #PAR_MIN})/2</code>.
+ * Calls {@link #add(int)} or {@link #remove} depending on whether the size
+ * needs to be increased or decreased to get the desired size.
+ * @return always false 
+ */
+public boolean execute()
+{
+       long time = CommonState.getTime();
+       int amplitude = (maxsize - minsize) / 2;
+       int newsize = (maxsize + minsize) / 2 + 
+         (int) (Math.sin(((double) time) / period * Math.PI) *
+         amplitude);
+       int diff = newsize - Network.size();
+       if (diff < 0)
+               remove(-diff);
+       else
+               add(diff);
+       
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/RandNI.java b/contrib/psg/src/peersim/dynamics/RandNI.java
new file mode 100644 (file)
index 0000000..7a4d5c7
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import peersim.core.*;
+import peersim.config.Configuration;
+
+/**
+ * Initializes the neighbor list of a node with random links.
+ */
+public class RandNI implements NodeInitializer {
+
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The protocol to operate on.
+ * @config
+ */
+private static final String PAR_PROT = "protocol";
+
+/**
+ * The number of samples (with replacement) to draw to initialize the
+ * neighbor list of the node.
+ * @config
+ */
+private static final String PAR_DEGREE = "k";
+
+/**
+ * If this config property is defined, method {@link Linkable#pack()} is 
+ * invoked on the specified protocol at the end of the wiring phase. 
+ * Default to false.
+ * @config
+ */
+private static final String PAR_PACK = "pack";
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/**
+ * The protocol we want to wire
+ */
+private final int pid;
+
+/**
+ * The degree of the regular graph
+ */
+private final int k;
+
+/**
+ * If true, method pack() is invoked on the initialized protocol
+ */
+private final boolean pack;
+
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters. Invoked by the
+ * simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public RandNI(String prefix)
+{
+       pid = Configuration.getPid(prefix + "." + PAR_PROT);
+       k = Configuration.getInt(prefix + "." + PAR_DEGREE);
+       pack = Configuration.contains(prefix + "." + PAR_PACK);
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Takes {@value #PAR_DEGREE} random samples with replacement from the nodes of
+ * the overlay network. No loop edges are added.
+ */
+public void initialize(Node n)
+{
+       if (Network.size() == 0) return;
+
+       Linkable linkable = (Linkable) n.getProtocol(pid);
+       for (int j = 0; j < k; ++j)
+       {
+               int r = CommonState.r.nextInt(Network.size());
+               linkable.addNeighbor(Network.get(r));
+       }
+
+       if (pack) linkable.pack();
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/StarNI.java b/contrib/psg/src/peersim/dynamics/StarNI.java
new file mode 100644 (file)
index 0000000..4dbd866
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.dynamics;
+
+import peersim.core.*;
+import peersim.config.Configuration;
+
+/**
+ * Initializes a node's neighbor list with a fixed center.
+ */
+public class StarNI implements NodeInitializer {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+
+/**
+ * The protocol to operate on.
+ * @config
+ */
+private static final String PAR_PROT = "protocol";
+
+/**
+ * If this config property is defined, method {@link Linkable#pack()} is 
+ * invoked on the specified protocol at the end of the wiring phase. 
+ * Default to false.
+ * @config
+ */
+private static final String PAR_PACK = "pack";
+
+/**
+ * The protocol we want to wire
+ */
+protected final int pid;
+
+/** If true, method pack() is invoked on the initialized protocol */
+protected final boolean pack;
+
+/**
+ * Used as center: nodes will link to this node.
+ */
+protected Node center = null;
+
+
+// ==================== initialization ==============================
+//===================================================================
+
+
+public StarNI(String prefix) {
+
+       pid = Configuration.getPid(prefix+"."+PAR_PROT);
+       pack = Configuration.contains(prefix+"."+PAR_PACK);
+}
+
+
+// ===================== public methods ==============================
+// ===================================================================
+
+
+/**
+ * Adds a link to a fixed node, the center. This fixed node remains the same
+ * throughout consecutive calls to this method. If the center fails in the
+ * meantime, a new one is chosen so care should be taken. The center is the
+ * first node that is not down (starting from node 0, 1, etc)
+ * at the time of the first call to the function. When a new center needs to
+ * be chosen (the current one is down), the new center is again the first
+ * one which is up. If no nodes are up, the node with the last index is set
+ * as center, and selection of a new center is always attempted when this
+ * method is called again.
+ */
+public void initialize(Node n) {
+       
+       if( Network.size() == 0 ) return;
+       
+       for(int i=0; (center==null || !center.isUp()) && i<Network.size(); ++i)
+               center=Network.get(i);
+       
+       ((Linkable)n.getProtocol(pid)).addNeighbor(center);
+       
+       if(pack)
+       {
+               ((Linkable)n.getProtocol(pid)).pack();
+       }
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/WireByMethod.java b/contrib/psg/src/peersim/dynamics/WireByMethod.java
new file mode 100644 (file)
index 0000000..de32a69
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import peersim.graph.*;
+import peersim.core.*;
+import peersim.config.*;
+import java.lang.reflect.*;
+import java.util.ArrayList;
+
+/**
+ * Takes a {@link Linkable} protocol and adds connections using an arbitrary
+ * method.
+ * No connections are removed.
+ * The connections are added by an arbitrary method that can be specified
+ * in the configuration. 
+ * The properties the method has to fulfill are the following
+ <ul>
+ <li>It MUST be static</li>
+ <li>It MUST have a first argument that can be assigned from a class
+ that implements {@link Graph}.</li>
+ <li>It MAY contain zero or more arguments following the first one.</li>
+ <li>All the arguments after the first one MUST be of primitive type int,
+ long or double, except
+ the last one, which MAY be of type that can be assigned from
+ <code>java.util.Random</code></li>
+ </ul>
+ The arguments are initialized using the configuration as follows.
+ <ul>
+ <li>The first argument is the {@link Graph} that is passed to
+ {@link #wire}.</li>
+ <li>The arguments after the first one (indexed as 1,2,etc) are initialized
+ from configuration parameters of the form {@value #PAR_ARG}i, where i is the
+ index.
+ <li>If the last argument can be assigned from 
+ <code>java.util.Random</code> then it is initialized with
+ {@link CommonState#r}, the central source of randomness for the
+ simulator.</li>
+ </ul>
+ For example, the class {@link WireWS} can be emulated by configuring
+ <pre>
+ init.0 WireByMethod
+ init.0.class GraphFactory
+ init.0.method wireWS
+ init.0.arg1 10
+ init.0.arg2 0.1
+ ...
+ </pre>
+ Note that the {@value #PAR_CLASS} parameter defaults to {@link GraphFactory},
+ and {@value #PAR_METHOD} defaults to "wire".
+ */
+public class WireByMethod extends WireGraph {
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The prefix for the configuration properties that describe parameters.
+ * @config
+ */
+private static final String PAR_ARG = "arg";
+
+/**
+* The class that has the method we want to use. Defaults to
+* {@link GraphFactory}.
+* @config
+*/
+private static final String PAR_CLASS = "class";
+
+/**
+* The name of the method for wiring the graph. Defaults to <code>wire</code>.
+* @config
+*/
+private static final String PAR_METHOD = "method";
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+private final Object[] args;
+
+private final Method method;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Loads configuration. It verifies the constraints defined
+ * in {@link WireByMethod}.
+ * @param prefix the configuration prefix for this class
+ */
+public WireByMethod(String prefix)
+{
+       super(prefix);
+       
+       // get the method
+       try
+       {
+               final Class wire =
+                       Configuration.getClass(prefix + "." + PAR_CLASS,
+               Class.forName("peersim.graph.GraphFactory"));
+               method = WireByMethod.getMethod(
+                       wire,
+                       Configuration.getString(prefix+"."+PAR_METHOD,"wire"));
+       }
+       catch( Exception e )
+       {
+               throw new RuntimeException(e);
+       }
+       
+       // set the constant args (those other than 0th)
+       Class[] argt = method.getParameterTypes();
+       args = new Object[argt.length];
+       for(int i=1; i<args.length; ++i)
+       {
+               
+               if( argt[i]==int.class )
+                       args[i]=Configuration.getInt(prefix+"."+PAR_ARG+i);
+               else if( argt[i]==long.class )
+                       args[i]=Configuration.getLong(prefix+"."+PAR_ARG+i);
+               else if( argt[i]==double.class )
+                       args[i]=Configuration.getDouble(prefix+"."+PAR_ARG+i);
+               else if(i==args.length-1 && argt[i].isInstance(CommonState.r))
+                       args[i]=CommonState.r;
+               else
+               {
+                       // we should neve get here
+                       throw new RuntimeException("Unexpected error, please "+
+                       "report this problem to the peersim team");
+               }
+       }
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Search a wiring method in the specified class.
+ * @param cl
+ *          the class where to find the method
+ * @param methodName
+ *          the method to be searched
+ * @return the requested method, if it fully conforms to the definition of
+ * the wiring methods.
+ */
+private static Method getMethod(Class cl, String methodName)
+               throws NoSuchMethodException, ClassNotFoundException {
+               
+       // Search methods
+       Method[] methods = cl.getMethods();
+       ArrayList<Method> list = new ArrayList<Method>();
+       for (Method m: methods) {
+               if (m.getName().equals(methodName)) {
+                       list.add(m);
+               }
+       }
+       
+       if (list.size() == 0) {
+               throw new NoSuchMethodException("No method "
+               + methodName + " in class " + cl.getSimpleName());
+       } else if (list.size() > 1) {
+               throw new NoSuchMethodException("Multiple methods called "
+               + methodName + " in class " + cl.getSimpleName());
+       }
+       
+       // Found a single method with the right name; check if
+       // it is a setter.
+       final Class graphClass = Class.forName("peersim.graph.Graph");
+       final Class randomClass = Class.forName("java.util.Random");
+       Method method = list.get(0);
+       Class[] pars = method.getParameterTypes();
+       if( pars.length < 1 || !pars[0].isAssignableFrom(graphClass) )
+               throw new NoSuchMethodException(method.getName() + " of class "
+               + cl.getSimpleName() + " is not a valid graph wiring method,"+
+               " it has to have peersim.graph.Graph as first argument type");
+       for(int i=1; i<pars.length; ++i)
+               if( !( pars[i]==int.class || pars[i]==long.class ||
+               pars[i]==double.class ||
+               (i==pars.length-1 && pars[i].isAssignableFrom(randomClass)) ) )
+                       throw new NoSuchMethodException(method.getName() +
+                       " of class "+ cl.getSimpleName()
+                       + " is not a valid graph wiring method");
+                       
+       if(method.toString().indexOf("static")<0)
+               throw new NoSuchMethodException(method.getName() +
+               " of class "+ cl.getSimpleName()
+               + " is not a valid graph wiring method; it is not static");
+       
+       return method;
+}
+
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/** Invokes the method passing g to it.*/
+public void wire(Graph g) {
+
+       args[0]=g;
+       try { method.invoke(null,args); }
+       catch( Exception e ) { throw new RuntimeException(e); }
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/WireFromFile.java b/contrib/psg/src/peersim/dynamics/WireFromFile.java
new file mode 100644 (file)
index 0000000..2b40636
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.dynamics;
+
+
+import java.io.IOException;
+import java.io.FileReader;
+import java.io.LineNumberReader;
+import java.util.StringTokenizer;
+import peersim.graph.Graph;
+import peersim.core.*;
+import peersim.config.Configuration;
+
+/**
+* Takes a {@link Linkable} protocol and adds connections that are stored in a
+* file. Note that no
+* connections are removed, they are only added. So it can be used in
+* combination with other initializers.
+* The format of the file is as follows. Each line begins with a node ID
+* (IDs start from 0) followed by a list of neighbors, separated by whitespace.
+* All node IDs larger than the actual network size will be discarded, but
+* it does not trigger an error. Lines starting with a "#" character and
+* empty lines are ignored.
+*/
+public class WireFromFile extends WireGraph {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+
+/** 
+*  The filename to load links from.
+*  @config
+*/
+private static final String PAR_FILE = "file";
+
+/** 
+*  The number of neighbors to be read from the file. If unset, the default
+* behavior is to read all links in the file. If set, then the first k
+* neighbors will be read only.
+*  @config
+*/
+private static final String PAR_K = "k";
+
+private final String file;
+
+private final int k;
+
+// ==================== initialization ==============================
+// ==================================================================
+
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireFromFile(String prefix) {
+
+       super(prefix);
+       file = Configuration.getString(prefix+"."+PAR_FILE);
+       k = Configuration.getInt(prefix + "." + PAR_K, Integer.MAX_VALUE);
+}
+
+
+// ===================== public methods ==============================
+// ===================================================================
+
+
+/**
+* Wires the graph from a file.
+* The format of the file is as follows. Each line begins with a node ID
+* (IDs start from 0) followed by a list of neighbors, separated by whitespace.
+* All node IDs larger than the actual network size will be discarded, but
+* it does not trigger an error. Lines starting with a "#" character and
+* empty lines are ignored.
+*/
+public void wire(Graph g) {
+try
+{
+       FileReader fr = new FileReader(file);
+       LineNumberReader lnr = new LineNumberReader(fr);
+       String line;
+       boolean wasOutOfRange=false;
+       while((line=lnr.readLine()) != null)
+       {
+               if( line.startsWith("#") ) continue;
+               StringTokenizer st = new StringTokenizer(line);
+               if(!st.hasMoreTokens()) continue;
+               
+               final int from = Integer.parseInt(st.nextToken());
+               if( from < 0 || from >= Network.size() )
+               {
+                       wasOutOfRange = true;
+                       continue;
+               }
+               
+               for(int i=0; i<k && st.hasMoreTokens(); ++i)
+               {
+                       final int to = Integer.parseInt(st.nextToken());
+                       if( to < 0 || to >= Network.size() )
+                               wasOutOfRange = true;
+                       else
+                               g.setEdge(from,to);
+               }
+       }
+
+       if( wasOutOfRange )
+               System.err.println("WireFromFile warning: in "+file+" "+
+                       "some nodes were out of range and so ignored.");
+       lnr.close();
+}
+catch( IOException e )
+{
+       throw new RuntimeException(e);
+}
+}
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/WireGraph.java b/contrib/psg/src/peersim/dynamics/WireGraph.java
new file mode 100644 (file)
index 0000000..4c8af15
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import peersim.graph.Graph;
+import peersim.core.*;
+import peersim.config.Configuration;
+
+/**
+ * This class is the superclass of classes that
+ * takes a {@link Linkable} protocol or a graph and add edges that define a
+ * certain topology.
+ * Note that no connections are removed, they are only added. So it can be used
+ * in combination with other initializers.
+ */
+public abstract class WireGraph implements Control
+{
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/**
+ * The {@link Linkable} protocol to operate on. If it is not specified,
+ * then operates on {@link #g}. If {@link #g} is null, {@link #execute} throws
+ * an Exception. Note that if {@link #g} is set, it will be used irrespective
+ * of the setting of the protocol in this field.
+ * @config
+ */
+private static final String PAR_PROT = "protocol";
+
+/**
+ * If this config property is defined, method {@link Linkable#pack()} is 
+ * invoked on the specified protocol at the end of the wiring phase. 
+ * Default to false.
+ * @config
+ */
+private static final String PAR_PACK = "pack";
+
+/**
+ * If set, the generated graph is undirected. In other words, for each link
+ * (i,j) a link (j,i) will also be added. Defaults to false.
+ * @config
+ */
+private static final String PAR_UNDIR = "undir";
+
+/**
+* Alias for {@value #PAR_UNDIR}.
+* @config
+*/
+private static final String PAR_UNDIR_ALT = "undirected";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/**
+ * The protocol we want to wire. It is negative if no protocol was set
+ * (in that case, a graph must be specified, see {@link #g}).
+ */
+protected final int pid;
+
+/** If true, method pack() is invoked on the initialized protocol */
+private final boolean pack;
+
+/** If true, edges are added in an undirected fashion.*/
+public final boolean undir;
+
+/**
+* If set (not null), this is the graph to wire. If null, the current overlay
+* is wired each time {@link #execute} is called, as specified by {@value
+* #PAR_PROT}.
+*/
+public Graph g=null;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters. Normally
+ * invoked by the simulation engine.
+ * @param prefix
+ *          the configuration prefix for this class
+ */
+protected WireGraph(String prefix) {
+
+       if( Configuration.contains(prefix + "." + PAR_PROT) )
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);
+       else
+               pid = -10;
+       pack = Configuration.contains(prefix + "." + PAR_PACK);
+       undir = (Configuration.contains(prefix + "." + PAR_UNDIR) |
+               Configuration.contains(prefix + "." + PAR_UNDIR_ALT));
+}
+
+
+//--------------------------------------------------------------------------
+//Public methods
+//--------------------------------------------------------------------------
+
+/**
+* Calls method {@link #wire} with the graph {@link #g},
+* or if null, on the overlay specified by the protocol given by config
+* parameter {@value #PAR_PROT}. If neither {@link #g}, nor {@value #PAR_PROT}
+* is set, throws a RuntimException.
+*/
+public final boolean execute() {
+
+       Graph gr;
+       if(g==null && pid==-10)
+       {
+               throw new RuntimeException(
+                       "Neither a protocol, nor a graph is specified.");
+       }
+       if(g==null) gr = new OverlayGraph(pid,!undir);
+       else gr=g;
+
+       if(gr.size()==0) return false;
+       wire(gr);
+       
+       if( g==null && pack)
+       {
+               int size = Network.size();
+               for (int i = 0; i < size; i++)
+               {
+                       Linkable link =
+                               (Linkable) Network.get(i).getProtocol(pid);
+                       link.pack();
+               }
+       }
+       return false;
+}
+
+//--------------------------------------------------------------------------
+
+/** The method that should wire (add edges to) the given graph. Has to
+* be implemented by extending classes */
+public abstract void wire(Graph g);
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/WireKOut.java b/contrib/psg/src/peersim/dynamics/WireKOut.java
new file mode 100644 (file)
index 0000000..927ddbd
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import peersim.graph.*;
+import peersim.core.*;
+import peersim.config.*;
+
+/**
+ * Takes a {@link Linkable} protocol and adds random connections. Note that no
+ * connections are removed, they are only added. So it can be used in
+ * combination with other initializers.
+ * @see GraphFactory#wireKOut
+ */
+public class WireKOut extends WireGraph {
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The number of outgoing edges to generate from each node.
+ * Passed to {@link GraphFactory#wireKOut}.
+ * No loop edges are generated.
+ * In the undirected case, the degree
+ * of nodes will be on average almost twice as much because the incoming links
+ * also become links out of each node.
+ * @config
+ */
+private static final String PAR_DEGREE = "k";
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/**
+ * The number of outgoing edges to generate from each node.
+ */
+private final int k;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireKOut(String prefix)
+{
+       super(prefix);
+       k = Configuration.getInt(prefix + "." + PAR_DEGREE);
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/** Calls {@link GraphFactory#wireKOut}. */
+public void wire(Graph g) {
+
+       GraphFactory.wireKOut(g,k,CommonState.r);
+}
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/WireRegRootedTree.java b/contrib/psg/src/peersim/dynamics/WireRegRootedTree.java
new file mode 100644 (file)
index 0000000..e8e0952
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import peersim.graph.*;
+import peersim.config.*;
+
+/**
+ * Takes a {@link peersim.core.Linkable} protocol and adds connections that
+ * define a regular
+ * rooted tree. Note that no
+ * connections are removed, they are only added. So it can be used in
+ * combination with other initializers.
+ * @see #wire
+ * @see GraphFactory#wireRegRootedTree
+ */
+public class WireRegRootedTree extends WireGraph {
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The parameter of the tree wiring method.
+ * It is passed to {@link GraphFactory#wireRegRootedTree}.
+ * @config
+ */
+private static final String PAR_DEGREE = "k";
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+private final int k;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireRegRootedTree(String prefix)
+{
+       super(prefix);
+       k = Configuration.getInt(prefix + "." + PAR_DEGREE);
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/** Calls {@link GraphFactory#wireRegRootedTree}. */
+public void wire(Graph g) {
+
+       GraphFactory.wireRegRootedTree(g,k);
+}
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/WireRingLattice.java b/contrib/psg/src/peersim/dynamics/WireRingLattice.java
new file mode 100644 (file)
index 0000000..a23822e
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import peersim.graph.*;
+import peersim.config.Configuration;
+
+/**
+ * Takes a {@link peersim.core.Linkable} protocol and adds edges that
+ * define a ring lattice.
+ * Note that no connections are removed, they are only added. So it can be used
+ * in combination with other initializers.
+ * @see  GraphFactory#wireRingLattice
+ */
+public class WireRingLattice extends WireGraph {
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/**
+ * The "lattice parameter" of the graph. The out-degree of the graph is equal to
+ * 2k. See {@link GraphFactory#wireRingLattice} (to which this parameter is
+ * passed) for further details.
+ * @config
+ */
+private static final String PAR_K = "k";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/**
+ */
+private final int k;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireRingLattice(String prefix)
+{
+       super(prefix);
+       k = Configuration.getInt(prefix + "." + PAR_K);
+}
+
+//--------------------------------------------------------------------------
+//Public methods
+//--------------------------------------------------------------------------
+
+/** calls {@link GraphFactory#wireRingLattice}. */
+public void wire(Graph g)
+{
+       GraphFactory.wireRingLattice(g, k);
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/WireScaleFreeBA.java b/contrib/psg/src/peersim/dynamics/WireScaleFreeBA.java
new file mode 100644 (file)
index 0000000..3b6ca30
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.graph.*;
+
+/**
+* This class contains the implementation of the Barabasi-Albert model
+* of growing scale free networks. The original model is described in
+* <a href="http://arxiv.org/abs/cond-mat/0106096">http://arxiv.org/abs/cond-mat/0106096</a>. It also contains the option of building
+* a directed network, in which case the model is a variation of the BA model
+* described in <a href="http://arxiv.org/pdf/cond-mat/0408391">
+http://arxiv.org/pdf/cond-mat/0408391</a>. In both cases, the number of the
+* initial set of nodes is the same as the degree parameter, and no links are
+* added. The first added node is connected to all of the initial nodes,
+* and after that the BA model is used normally.
+* @see GraphFactory#wireScaleFreeBA
+*/
+public class WireScaleFreeBA extends WireGraph {
+
+
+// ================ constants ============================================
+// =======================================================================
+
+/**
+ * The number of edges added to each new node (apart from those forming the 
+ * initial network).
+ * Passed to {@link GraphFactory#wireScaleFreeBA}.
+ * @config
+ */
+private static final String PAR_DEGREE = "k";
+
+
+// =================== fields ============================================
+// =======================================================================
+
+/** Parameter of the BA model. */
+private int k;
+
+// ===================== initialization ==================================
+// =======================================================================
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+*/
+public WireScaleFreeBA(String prefix)
+{
+       super(prefix);
+       k = Configuration.getInt(prefix + "." + PAR_DEGREE);
+}
+
+
+// ======================== methods =======================================
+// ========================================================================
+
+
+/** calls {@link GraphFactory#wireScaleFreeBA}.*/
+public void wire(Graph g) {
+       
+       GraphFactory.wireScaleFreeBA(g,k,CommonState.r );
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/WireScaleFreeDM.java b/contrib/psg/src/peersim/dynamics/WireScaleFreeDM.java
new file mode 100644 (file)
index 0000000..06ae973
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import peersim.graph.Graph;
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Wires a scale free graph using a method described in
+ * <a href="http://xxx.lanl.gov/abs/cond-mat/0106144">this paper</a>.
+ * It is an incremental technique, where the new nodes are connected to
+ * the two ends of an edge that is already in the network.
+ * This model always wires undirected links.
+ */
+public class WireScaleFreeDM extends WireGraph {
+
+
+//--------------------------------------------------------------------------
+// Constants
+//--------------------------------------------------------------------------
+
+/** 
+ * The number of edges added to each new
+ * node (apart from those forming the initial network) is twice this
+ * value.
+ * @config
+ */
+private static final String PAR_EDGES = "k";
+
+
+//--------------------------------------------------------------------------
+// Fields
+//--------------------------------------------------------------------------
+
+
+/** The number of edges created for a new node is 2*k. */      
+private final int k;
+
+
+//--------------------------------------------------------------------------
+// Constructor
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireScaleFreeDM(String prefix)
+{
+       super(prefix);
+       k = Configuration.getInt(prefix + "." + PAR_EDGES);
+}
+
+
+//--------------------------------------------------------------------------
+// Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Wires a scale free graph using a method described in
+ * <a href="http://xxx.lanl.gov/abs/cond-mat/0106144">this paper</a>.
+ * It is an incremental technique, where the new nodes are connected to
+ * the two ends of an edge that is already in the network.
+ * This model always wires undirected links.
+*/
+public void wire(Graph g) {
+
+       int nodes=g.size();
+       int[] links = new int[4*k*nodes];
+
+       // Initial number of nodes connected as a clique
+       int clique = (k > 3 ? k : 3);
+
+       // Add initial edges, to form a clique
+       int len=0;
+       for (int i=0; i < clique; i++)
+       for (int j=0; j < clique; j++)
+       {
+               if (i != j)
+               {
+                       g.setEdge(i,j);
+                       g.setEdge(j,i);
+                       links[len*2] = i;
+                       links[len*2+1] = j;
+                       len++;
+               }
+       }
+
+       for (int i=clique; i < nodes; i++)
+       for (int l=0; l < k; l++)
+       {
+               int edge = CommonState.r.nextInt(len);
+               int m = links[edge*2];
+               int j = links[edge*2+1];
+               g.setEdge(i, m);
+               g.setEdge(m, i);
+               g.setEdge(j, m);
+               g.setEdge(m, j);
+               links[len*2] = i;
+               links[len*2+1] = m;
+               len++;
+               links[len*2] = j;
+               links[len*2+1] = m;
+               len++;
+       }
+}
+               
+}
diff --git a/contrib/psg/src/peersim/dynamics/WireStar.java b/contrib/psg/src/peersim/dynamics/WireStar.java
new file mode 100644 (file)
index 0000000..0f11b64
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.dynamics;
+
+import peersim.graph.*;
+
+/**
+ * Takes a {@link peersim.core.Linkable} protocol and adds connection
+ * which for a star
+ * topology. No connections are removed, they are only added. So it can be used
+ * in combination with other initializers.
+ * @see GraphFactory#wireStar
+ */
+public class WireStar extends WireGraph {
+
+// ===================== initialization ==============================
+// ===================================================================
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireStar(String prefix) { super(prefix); }
+
+// ===================== public methods ==============================
+// ===================================================================
+
+
+/** Calls {@link GraphFactory#wireStar}.*/
+public void wire(Graph g) {
+       
+       GraphFactory.wireStar(g);
+}
+
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/WireWS.java b/contrib/psg/src/peersim/dynamics/WireWS.java
new file mode 100644 (file)
index 0000000..65cefed
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.dynamics;
+
+import peersim.graph.*;
+import peersim.core.*;
+import peersim.config.Configuration;
+
+/**
+* Takes a {@link Linkable} protocol and adds connections following the
+* small-world model of Watts and Strogatz. Note that no
+* connections are removed, they are only added. So it can be used in
+* combination with other initializers.
+* @see GraphFactory#wireWS
+*/
+public class WireWS extends WireGraph {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+/**
+ * The beta parameter of a Watts-Strogatz graph represents the probability for a
+ * node to be re-wired.
+ * Passed to {@link GraphFactory#wireWS}.
+ * @config
+ */
+private static final String PAR_BETA = "beta";
+
+/**
+ * The degree of the graph. See {@link GraphFactory#wireRingLattice}.
+ * Passed to {@link GraphFactory#wireWS}.
+ * @config
+ */
+private static final String PAR_DEGREE = "k";
+
+/**
+ * The degree of the regular graph
+ */
+private final int k;
+
+/**
+ * The degree of the regular graph
+ */
+private final double beta;
+
+
+// ==================== initialization ==============================
+//===================================================================
+
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireWS(String prefix) {
+
+       super(prefix);
+       k = Configuration.getInt(prefix+"."+PAR_DEGREE);
+       beta = Configuration.getDouble(prefix+"."+PAR_BETA);
+}
+
+
+// ===================== public methods ==============================
+// ===================================================================
+
+
+/** calls {@link GraphFactory#wireWS}.*/
+public void wire(Graph g) {
+
+       GraphFactory.wireWS(g,k,beta,CommonState.r);
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/edsim/CDScheduler.java b/contrib/psg/src/peersim/edsim/CDScheduler.java
new file mode 100644 (file)
index 0000000..f864ff5
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.*;
+import peersim.cdsim.CDProtocol;
+import peersim.config.*;
+import peersim.dynamics.NodeInitializer;
+
+/**
+ * Schedules the first execution of the cycle based protocol instances in the
+ * event driven engine. It implements {@link Control} but it will most often be
+ * invoked only once for each protocol as an initializer, since the scheduled
+ * events schedule themselves for the consecutive executions (see
+ * {@link NextCycleEvent}).
+ *
+ * <p>
+ * All {@link CDProtocol} specifications in the configuration need to contain a
+ * {@link Scheduler} specification at least for the step size (see config
+ * parameter {@value peersim.core.Scheduler#PAR_STEP} of {@link Scheduler}).
+ * This value is used as the cycle length for the corresponding protocol.
+ *
+ * @see NextCycleEvent
+ */
+public class CDScheduler implements Control, NodeInitializer {
+
+       // ============================== fields ==============================
+       // ====================================================================
+
+       /**
+        * Parameter that is used to define the class that is used to schedule the
+        * next cycle. Its type is (or extends) {@link NextCycleEvent}. Defaults to
+        * {@link NextCycleEvent}.
+        * 
+        * @config
+        */
+       private static final String PAR_NEXTC = "nextcycle";
+
+       /**
+        * The protocols that this scheduler schedules for the first execution. It
+        * might contain several protocol names, separated by whitespace. All
+        * protocols will be scheduled based on the common parameter set for this
+        * scheduler and the parameters of the protocol (cycle length). Protocols
+        * are scheduled independently of each other.
+        * 
+        * @config
+        */
+       private static final String PAR_PROTOCOL = "protocol";
+
+       /**
+        * If set, it means that the initial execution of the given protocol is
+        * scheduled for a different random time for all nodes. The random time is a
+        * sample between the current time (inclusive) and the cycle length
+        * (exclusive), the latter being specified by the step parameter (see
+        * {@link Scheduler}) of the assigned protocol.
+        * 
+        * @see #execute
+        * @config
+        */
+       private static final String PAR_RNDSTART = "randstart";
+
+       /**
+        * Contains the scheduler objects for all {@link CDProtocol}s defined in the
+        * configuration. The length of the array is the number of protocols
+        * defined, but those entries that belong to protocols that are not
+        * {@link CDProtocol}s are null.
+        */
+       public static final Scheduler[] sch;
+
+       private final NextCycleEvent[] nce;
+
+       private final int[] pid;
+
+       private final boolean randstart;
+
+       // =============================== initialization ======================
+       // =====================================================================
+
+       /**
+        * Loads protocol schedulers for all protocols.
+        */
+       static {
+
+               String[] names = Configuration.getNames(Node.PAR_PROT);
+               sch = new Scheduler[names.length];
+               for (int i = 0; i < names.length; ++i) {
+                       if (Network.prototype.getProtocol(i) instanceof CDProtocol)
+                               // with no default values for step to avoid
+                               // "overscheduling" due to lack of step option.
+                               sch[i] = new Scheduler(names[i], false);
+               }
+       }
+
+       // --------------------------------------------------------------------
+
+       /**
+        * Initialization based on configuration parameters.
+        */
+       public CDScheduler(String n) {
+               String[] prots = Configuration.getString(n + "." + PAR_PROTOCOL).split("\\s");
+               pid = new int[prots.length];
+               nce = new NextCycleEvent[prots.length];
+               for (int i = 0; i < prots.length; ++i) {
+                       pid[i] = Configuration.lookupPid(prots[i]);
+                       if (!(Network.prototype.getProtocol(pid[i]) instanceof CDProtocol)) {
+                               throw new IllegalParameterException(n + "." + PAR_PROTOCOL,
+                                               "Only CDProtocols are accepted here");
+                       }
+                       nce[i] = (NextCycleEvent) Configuration.getInstance(n + "."
+                                       + PAR_NEXTC, new NextCycleEvent(null));
+               }
+               randstart = Configuration.contains(n + "." + PAR_RNDSTART);
+       }
+
+       // ========================== methods ==================================
+       // =====================================================================
+
+       /**
+        * Schedules the protocol at all nodes for the first execution adding it to
+        * the priority queue of the event driven simulation. The time of the first
+        * execution is determined by {@link #firstDelay}. The implementation calls
+        * {@link #initialize} for all nodes.
+        * 
+        * @see #initialize
+        */
+       public boolean execute() {
+
+               for (int i = 0; i < Network.size(); ++i) {
+                       initialize(Network.get(i));
+               }
+
+               return false;
+       }
+
+       // --------------------------------------------------------------------
+
+       /**
+        * Schedules the protocol at given node for the first execution adding it to
+        * the priority queue of the event driven simulation. The time of the first
+        * execution is determined by a reference point in time and
+        * {@link #firstDelay}, which defines the delay from the reference point.
+        * The reference point is the maximum of the current time, and the value of
+        * parameter {@value peersim.core.Scheduler#PAR_FROM} of the protocol being
+        * scheduled. If the calculated time of the first execution is not valid
+        * according to the schedule of the protocol then no execution is scheduled
+        * for that protocol.
+        * <p>
+        * A final note: for performance reasons, the recommended practice is not to
+        * use parameter {@value peersim.core.Scheduler#PAR_FROM} in protocols, but
+        * to schedule {@link CDScheduler} itself for the desired time, whenever
+        * possible (e.g., it is not possible if {@link CDScheduler} is used as a
+        * {@link NodeInitializer}).
+        */
+       public void initialize(Node n) {
+               /*
+                * XXX If "from" is not the current time and this is used as a control
+                * (not node initializer) then we dump _lots_ of events in the queue
+                * that are just stored there until "from" comes. This reduces
+                * performance, and should be fixed. When fixed, the final comment can
+                * be removed from the docs.
+                */
+
+               final long time = CommonState.getTime();
+               for (int i = 0; i < pid.length; ++i) {
+                       Object nceclone = null;
+                       try {
+                               nceclone = nce[i].clone();
+                       } catch (CloneNotSupportedException e) {
+                       } // cannot possibly happen
+
+                       final long delay = firstDelay(sch[pid[i]].step);
+                       final long nexttime = Math.max(time, sch[pid[i]].from) + delay;
+                       if (nexttime < sch[pid[i]].until)
+                               EDSimulator.add(nexttime - time, nceclone, n, pid[i]);
+               }
+       }
+
+       // --------------------------------------------------------------------
+
+       /**
+        * Returns the time (through giving the delay from the current time) when
+        * this even is first executed. If {@value #PAR_RNDSTART} is not set, it
+        * returns zero, otherwise a random value between 0, inclusive, and
+        * cyclelength, exclusive.
+        * 
+        * @param cyclelength
+        *            The cycle length of the cycle based protocol for which this
+        *            method is called
+        */
+       protected long firstDelay(long cyclelength) {
+
+               if (randstart)
+                       return CommonState.r.nextLong(cyclelength);
+               else
+                       return 0;
+       }
+}
diff --git a/contrib/psg/src/peersim/edsim/ControlEvent.java b/contrib/psg/src/peersim/edsim/ControlEvent.java
new file mode 100644 (file)
index 0000000..8c12d3a
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.Control;
+import peersim.core.Scheduler;
+
+
+/**
+ * Wrapper for {@link Control}s to be executed in an event driven simulation.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.5 $
+ */
+class ControlEvent
+{
+
+//---------------------------------------------------------------------
+//Fields
+//---------------------------------------------------------------------
+
+/** 
+ * The reference to the dynamics to be executed; null if this cycle event
+ * refers to an observer.
+ */
+private Control control;
+
+/** Order index used to maintain order between cycle-based events */
+private int order;
+
+
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/** 
+ * Scheduler object to obtain the next schedule time of this event 
+ */
+private Scheduler scheduler;
+
+/**
+ * Creates a cycle event for a control object. It also schedules the object
+ * for the first execution adding it to the priority queue of the event driven
+ * simulation.
+ */
+public ControlEvent(Control control, Scheduler scheduler, int order)
+{
+       this.control = control;
+       this.order = order;
+       this.scheduler = scheduler;
+       long next = scheduler.getNext();
+       if( next>=0 ) EDSimulator.addControlEvent(next, order, this);
+}
+
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/**
+* Executes the control object, and schedules the object for the next execution
+* adding it to the priority queue of the event driven simulation.
+*/
+public boolean execute() {
+
+       boolean ret = control.execute();
+       long next = scheduler.getNext();
+       if( next>=0 ) EDSimulator.addControlEvent(next, order, this);
+       return ret;
+}
+
+}
+
+
diff --git a/contrib/psg/src/peersim/edsim/EDProtocol.java b/contrib/psg/src/peersim/edsim/EDProtocol.java
new file mode 100644 (file)
index 0000000..60c83a2
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.edsim;
+
+import peersim.core.*;
+
+/**
+ * The interface to be implemented by protocols run under the event-driven
+ * model. A single method is provided, to deliver events to the protocol.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.5 $
+ */
+public interface EDProtocol 
+extends Protocol 
+{
+
+       /**
+       * This method is invoked by the scheduler to deliver events to the
+       * protocol. Apart from the event object, information about the node
+       * and the protocol identifier are also provided. Additional information
+       * can be accessed through the {@link CommonState} class.
+       * 
+       * @param node the local node
+       * @param pid the identifier of this protocol
+       * @param event the delivered event
+       */
+       public void processEvent( Node node, int pid, Object event );
+
+}
+
diff --git a/contrib/psg/src/peersim/edsim/EDSimulator.java b/contrib/psg/src/peersim/edsim/EDSimulator.java
new file mode 100644 (file)
index 0000000..e56d021
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import java.util.Arrays;
+
+import peersim.Simulator;
+import peersim.config.*;
+import peersim.core.*;
+import psgsim.PSGSimulator;
+
+/**
+ * Event-driven simulator engine. It is a fully static singleton class. For an
+ * event driven simulation the configuration has to describe a set of
+ * {@link Protocol}s, a set of {@link Control}s and their ordering and a set of
+ * initializers and their ordering. See parameters {@value #PAR_INIT},
+ * {@value #PAR_CTRL}.
+ * <p>
+ * One experiment run by {@link #nextExperiment} works as follows. First the
+ * initializers are run in the specified order. Then the first execution of all
+ * specified controls is scheduled in the event queue. This scheduling is
+ * defined by the {@link Scheduler} parameters of each control component. After
+ * this, the first event is taken from the event queue. If the event wraps a
+ * control, the control is executed, otherwise the event is delivered to the
+ * destination protocol, that must implement {@link EDProtocol}. This is
+ * iterated while the current time is less than {@value #PAR_ENDTIME} or the
+ * queue becomes empty. If more control events fall at the same time point, then
+ * the order given in the configuration is respected. If more non-control events
+ * fall at the same time point, they are processed in a random order.
+ * <p>
+ * The engine also provides the interface to add events to the queue. Note that
+ * this engine does not explicitly run the protocols. In all cases at least one
+ * control or initializer has to be defined that sends event(s) to protocols.
+ * <p>
+ * Controls can be scheduled (using the {@link Scheduler} parameters in the
+ * configuration) to run after the experiment has finished. That is, each
+ * experiment is finished by running the controls that are scheduled to be run
+ * after the experiment.
+ * <p>
+ * Any control can interrupt an experiment at any time it is executed by
+ * returning true in method {@link Control#execute}. However, the controls
+ * scheduled to run after the experiment are still executed completely,
+ * irrespective of their return value and even if the experiment was
+ * interrupted.
+ * <p>
+ * {@link CDScheduler} has to be mentioned that is a control that can bridge the
+ * gap between {@link peersim.cdsim} and the event driven engine. It can wrap
+ * {@link peersim.cdsim.CDProtocol} appropriately so that the execution of the
+ * cycles are scheduled in configurable ways for each node individually. In some
+ * cases this can add a more fine-grained control and more realism to
+ * {@link peersim.cdsim.CDProtocol} simulations, at the cost of some loss in
+ * performance.
+ * <p>
+ * When protocols at different nodes send messages to each other, they might
+ * want to use a model of the transport layer so that in the simulation message
+ * delay and message omissions can be modeled in a modular way. This
+ * functionality is implemented in package {@link peersim.transport}.
+ * 
+ * @see Configuration
+ */
+public class EDSimulator {
+
+       // ---------------------------------------------------------------------
+       // Parameters
+       // ---------------------------------------------------------------------
+
+       /**
+        * The ending time for simulation. Only events that have a strictly smaller
+        * value are executed. It must be positive. Although in principle negative
+        * timestamps could be allowed, we assume time will be positive.
+        * 
+        * @config
+        */
+       public static final String PAR_ENDTIME = "simulation.endtime";
+
+       /**
+        * This parameter specifies how often the simulator should log the current
+        * time on the standard error. The time is logged only if there were events
+        * in the respective interval, and only the time of some actual event is
+        * printed. That is, the actual log is not guaranteed to happen in identical
+        * intervals of time. It is merely a way of seeing whether the simulation
+        * progresses and how fast...
+        * 
+        * @config
+        */
+       private static final String PAR_LOGTIME = "simulation.logtime";
+
+       /**
+        * This parameter specifies the event queue to be used. It must be an
+        * implementation of interface {@link PriorityQ}. If it is not defined, the
+        * internal implementation is used.
+        * 
+        * @config
+        */
+       private static final String PAR_PQ = "simulation.eventqueue";
+
+       /**
+        * This is the prefix for initializers. These have to be of type
+        * {@link Control}. They are run at the beginning of each experiment, in the
+        * order specified by the configuration.
+        * 
+        * @see Configuration
+        * @config
+        * @config
+        */
+       private static final String PAR_INIT = "init";
+
+       /**
+        * This is the prefix for {@link Control} components. They are run at the
+        * time points defined by the {@link Scheduler} associated to them. If some
+        * controls have to be executed at the same time point, they are executed in
+        * the order specified in the configuration.
+        * 
+        * @see Configuration
+        * @config
+        */
+       private static final String PAR_CTRL = "control";
+
+       // ---------------------------------------------------------------------
+       // Fields
+       // ---------------------------------------------------------------------
+
+       /** Maximum time for simulation */
+       private static long endtime;
+
+       /** Log time */
+       private static long logtime;
+
+       /** holds the modifiers of this simulation */
+       private static Control[] controls = null;
+
+       /** Holds the control schedulers of this simulation */
+       private static Scheduler[] ctrlSchedules = null;
+
+       /** Ordered list of events (heap) */
+       private static PriorityQ heap = null;
+
+       private static long nextlog = 0;
+
+       // =============== initialization ======================================
+       // =====================================================================
+
+       /** to prevent construction */
+       private EDSimulator() {
+       }
+
+       // ---------------------------------------------------------------------
+       // Private methods
+       // ---------------------------------------------------------------------
+
+       /**
+        * Load and run initializers.
+        */
+       private static void runInitializers() {
+
+               Object[] inits = Configuration.getInstanceArray(PAR_INIT);
+               String names[] = Configuration.getNames(PAR_INIT);
+
+               for (int i = 0; i < inits.length; ++i) {
+
+                       System.err.println("- Running initializer " + names[i] + ": "
+                                       + inits[i].getClass());
+                       ((Control) inits[i]).execute();
+               }
+       }
+
+       // --------------------------------------------------------------------
+
+       private static void scheduleControls() {
+               // load controls
+               String[] names = Configuration.getNames(PAR_CTRL);
+               controls = new Control[names.length];
+               ctrlSchedules = new Scheduler[names.length];
+               for (int i = 0; i < names.length; ++i) {
+                       controls[i] = (Control) Configuration.getInstance(names[i]);
+                       ctrlSchedules[i] = new Scheduler(names[i], false);
+               }
+               System.err.println("EDSimulator: loaded controls "
+                               + Arrays.asList(names));
+
+               // Schedule controls execution
+               if (controls.length > heap.maxPriority() + 1)
+                       throw new IllegalArgumentException("Too many control objects");
+               for (int i = 0; i < controls.length; i++) {
+                       new ControlEvent(controls[i], ctrlSchedules[i], i);
+               }
+       }
+
+       // ---------------------------------------------------------------------
+
+       /**
+        * Adds a new event to be scheduled, specifying the number of time units of
+        * delay, and the execution order parameter.
+        * 
+        * @param time
+        *            The actual time at which the next event should be scheduled.
+        * @param order
+        *            The index used to specify the order in which control events
+        *            should be executed, if they happen to be at the same time,
+        *            which is typically the case.
+        * @param event
+        *            The control event
+        */
+       static void addControlEvent(long time, int order, ControlEvent event) {
+               // we don't check whether time is negative or in the past: we trust
+               // the caller, which must be from this package
+               if (time >= endtime)
+                       return;
+               heap.add(time, event, null, (byte) 0, order);
+       }
+
+       // ---------------------------------------------------------------------
+
+       /**
+        * This method is used to check whether the current configuration can be
+        * used for event driven simulations. It checks for the existence of config
+        * parameter {@value #PAR_ENDTIME}.
+        */
+       public static final boolean isConfigurationEventDriven() {
+               return Configuration.contains(PAR_ENDTIME);
+       }
+
+       // ---------------------------------------------------------------------
+
+       /**
+        * Execute and remove the next event from the ordered event list.
+        * 
+        * @return true if the execution should be stopped.
+        */
+       private static boolean executeNext() {
+               PriorityQ.Event ev = heap.removeFirst();
+               if (ev == null) {
+                       System.err.println("EDSimulator: queue is empty, quitting"
+                                       + " at time " + CommonState.getTime());
+                       return true;
+               }
+
+               long time = ev.time;
+
+               if (time >= nextlog) {
+                       // System.err.println("Current time: " + time);
+                       // seemingly complicated: to prevent overflow
+                       while (time - nextlog >= logtime)
+                               nextlog += logtime;
+                       if (endtime - nextlog >= logtime)
+                               nextlog += logtime;
+                       else
+                               nextlog = endtime;
+               }
+               if (time >= endtime) {
+                       System.err.println("EDSimulator: reached end time, quitting,"
+                                       + " leaving " + heap.size()
+                                       + " unprocessed events in the queue");
+                       return true;
+               }
+
+               CommonState.setTime(time);
+               int pid = ev.pid;
+                       if (ev.node == null) {
+                       // might be control event; handled through a special method
+                       ControlEvent ctrl = null;
+                       try {
+                               ctrl = (ControlEvent) ev.event;
+                       } catch (ClassCastException e) {
+                               throw new RuntimeException(
+                                               "No destination specified (null) for event " + ev);
+                       }
+                       return ctrl.execute();
+               } else if (ev.node != Network.prototype && ev.node.isUp()) {
+                       CommonState.setPid(pid);
+                       CommonState.setNode(ev.node);
+                       if (ev.event instanceof NextCycleEvent) {
+                               NextCycleEvent nce = (NextCycleEvent) ev.event;
+                               nce.execute();
+                       } else {
+                               EDProtocol prot = null;
+                               try {
+                                       prot = (EDProtocol) ev.node.getProtocol(pid);
+                                       // System.out.println("prot "+prot.getClass().getName());
+                               } catch (ClassCastException e) {
+                                       e.printStackTrace();
+                                       throw new IllegalArgumentException("Protocol "
+                                                       + Configuration.lookupPid(pid)
+                                                       + " does not implement EDProtocol; "
+                                                       + ev.event.getClass());
+                               }
+                               prot.processEvent(ev.node, pid, ev.event);
+                       }
+               }
+
+               return false;
+       }
+
+       // ---------------------------------------------------------------------
+       // Public methods
+       // ---------------------------------------------------------------------
+
+       /**
+        * Runs an experiment, resetting everything except the random seed.
+        */
+       public static void nextExperiment() {
+               // Reading parameter
+               if (Configuration.contains(PAR_PQ))
+                       heap = (PriorityQ) Configuration.getInstance(PAR_PQ);
+               else
+                       heap = new Heap();
+               endtime = Configuration.getLong(PAR_ENDTIME);
+               if (CommonState.getEndTime() < 0) // not initialized yet
+                       CommonState.setEndTime(endtime);
+               if (heap.maxTime() < endtime)
+                       throw new IllegalParameterException(PAR_ENDTIME,
+                                       "End time is too large: configured event queue only"
+                                                       + " supports " + heap.maxTime());
+               logtime = Configuration.getLong(PAR_LOGTIME, Long.MAX_VALUE);
+
+               // initialization
+               System.err.println("EDSimulator: resetting");
+               CommonState.setPhase(CommonState.PHASE_UNKNOWN);
+               CommonState.setTime(0); // needed here
+               controls = null;
+               ctrlSchedules = null;
+               nextlog = 0;
+               Network.reset();
+               System.err.println("EDSimulator: running initializers");
+               runInitializers();
+               scheduleControls();
+                       // Perform the actual simulation; executeNext() will tell when to
+               // stop.
+               boolean exit = false;
+               while (!exit) {
+                       exit = executeNext();
+               }
+
+               // analysis after the simulation
+               CommonState.setPhase(CommonState.POST_SIMULATION);
+               for (int j = 0; j < controls.length; ++j) {
+                       if (ctrlSchedules[j].fin)
+                               controls[j].execute();
+               }
+
+       }
+
+       // ---------------------------------------------------------------------
+
+       /**
+        * Adds a new event to be scheduled, specifying the number of time units of
+        * delay, and the node and the protocol identifier to which the event will
+        * be delivered.
+        * 
+        * @param delay
+        *            The number of time units before the event is scheduled. Has to
+        *            be non-negative.
+        * @param event
+        *            The object associated to this event
+        * @param node
+        *            The node associated to the event.
+        * @param pid
+        *            The identifier of the protocol to which the event will be
+        *            delivered
+        */
+       public static void add(long delay, Object event, Node node, int pid) {
+               //if (event instanceof NextCycleEvent)
+                       //System.err.println("************* edsim delay="+delay +" pid="+pid+" event="+event+" time="+CommonState.getTime());
+               if (Simulator.getSimID() == 2){
+                       PSGSimulator.add(delay, event, node, pid);
+               }
+               
+               else {
+                       if (delay < 0)
+                               throw new IllegalArgumentException("Protocol "
+                                               + node.getProtocol(pid) + " is trying to add event "
+                                               + event + " with a negative delay: " + delay);
+                       if (pid > Byte.MAX_VALUE)
+                               throw new IllegalArgumentException(
+                                               "This version does not support more than "
+                                                               + Byte.MAX_VALUE + " protocols");
+
+                       long time = CommonState.getTime();
+                       if (endtime - time > delay) // check like this to deal with overflow
+                               heap.add(time + delay, event, node, (byte) pid);
+               }
+       }
+
+}
diff --git a/contrib/psg/src/peersim/edsim/Heap.java b/contrib/psg/src/peersim/edsim/Heap.java
new file mode 100644 (file)
index 0000000..eb123ac
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2001 The Anthill Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.Node;
+import peersim.core.CommonState;
+import peersim.config.Configuration;
+import peersim.config.IllegalParameterException;
+
+/**
+ *  The Heap data structure used to maintain events "sorted" by 
+ *  scheduled time and to obtain the next event to be executed.
+ *  
+ *  @author Alberto Montresor
+ *  @version $Revision: 1.10 $
+ */
+public class Heap implements PriorityQ {
+
+//--------------------------------------------------------------------------
+// Constants
+//--------------------------------------------------------------------------
+
+/** 
+ * This parameter specifies how many
+ * bits are used to order events that occur at the same time. Defaults
+ * to 8. A value smaller than 8 causes an IllegalParameterException.
+ * Higher values allow for a better discrimination, but reduce
+ * the maximal time steps that can be simulated.
+ * @config 
+ */    
+private static final String PAR_PBITS = "pbits";
+private static final String PAR_PBITS_LEGACY = "simulation.timebits";
+
+/** 
+ * Specifies the initial capacity of the heap. Defaults to 65536.
+ * @config 
+ */    
+private static final String PAR_SIZE = "size";
+
+
+//--------------------------------------------------------------------------
+// Fields
+//--------------------------------------------------------------------------
+
+// The following arrays are four heaps ordered by time. The alternative
+// approach (i.e. to store event objects) requires much more memory,
+// and based on some tests that I've done is not really much faster.
+
+/** Event component of the heap */
+private Object[] events;
+
+/** Time component of the heap */
+private long[] times;
+
+/** Node component of the heap */
+private Node[] nodes;
+
+/** Pid component of the heap */
+private byte[] pids;
+
+/** Number of elements */
+private int size;
+
+/** Singleton event object used to return (event, time, node, pid) tuples */
+private final Event ev = new Event();
+
+/** The number of bits reserved to order event with the same timestamp */
+private final int pbits;
+
+/** The mask to test whether the time value fits into the range we can
+represent */
+private final long overflowMask;
+
+//--------------------------------------------------------------------------
+// Contructor
+//--------------------------------------------------------------------------
+
+/**
+ * Initializes a new heap using defaults.
+ */
+public Heap() {
+       this(""); // "" is not a valid prefix for a component
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Initializes a new heap using the configuration.
+ */
+public Heap(String prefix) {
+
+       int size = Configuration.getInt(prefix+"."+PAR_SIZE,65536);
+       
+       // some complex stuff to deal with legacy parameter names...
+       if( !Configuration.contains(PAR_PBITS_LEGACY) )
+               pbits = Configuration.getInt(prefix+"."+PAR_PBITS,8);
+       else
+       {
+               pbits = Configuration.getInt(PAR_PBITS_LEGACY);
+               if( Configuration.contains(prefix+"."+PAR_PBITS) )
+                       throw new IllegalParameterException(PAR_PBITS_LEGACY,
+                               "Your configuration file contains both "+
+                               prefix+"."+PAR_PBITS+ " and "+
+                               PAR_PBITS_LEGACY+"; please remove "+
+                               PAR_PBITS_LEGACY);
+       }
+
+       if (pbits < 8 || pbits >= 31) {
+               throw new IllegalParameterException(prefix+"."+PAR_PBITS,
+               "This parameter should be >= 8 or < 31");
+       }
+       overflowMask = ~maxTime();
+       events = new Object[size];
+       times = new long[size];
+       nodes = new Node[size];
+       pids = new byte[size];
+}
+
+//--------------------------------------------------------------------------
+// Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Returns the current number of events in the system.
+ */
+public int size()
+{
+       return size;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Add a new event, to be scheduled at the specified time.
+ * 
+ * @param time the time at which this event should be scheduled
+ * @param event the object describing the event
+ * @param node the node at which the event has to be delivered
+ * @param pid the protocol that handles the event
+ */
+public void add(long time, Object event, Node node, byte pid) 
+{
+       add(time,event,node,pid,CommonState.r.nextInt(1 << pbits));
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Add a new event, to be scheduled at the specified time.
+ * 
+ * @param time the time at which this event should be scheduled
+ * @param event the object describing the event
+ * @param node the node at which the event has to be delivered
+ * @param pid the protocol that handles the event
+ */
+public void add(long time, Object event, Node node, byte pid, long priority) 
+{
+       if( (time&overflowMask) != 0 ) throw new
+               IllegalArgumentException("Time overflow: time="+time);
+//XXX should we test priority overflow? How much does it cost?
+       
+       time = (time << pbits) | priority;
+       
+       size++;
+       int pos = size;
+       put(pos, time, event, node, pid);
+       while (pos > 1 && getTime(pos / 2) > time) {
+               swap(pos, pos / 2);
+               pos = pos / 2;
+       }
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Removes the first event in the heap and returns it.
+ * Note that, to avoid garbage collection, a singleton instance of
+ * the Event class is used. This means that data contained in the
+ * returned event are overwritten when a new invocation of this
+ * method is performed.
+ * @return first event or null if size is zero
+ */
+public Event removeFirst() {
+       
+       if(size==0) return null;
+
+       ev.time = times[0] >> pbits;
+       ev.event = events[0];
+       ev.node = nodes[0];
+       ev.pid = pids[0];
+       swap(1, size);
+       size--;
+       minHeapify(1);
+       return ev;
+}
+
+//--------------------------------------------------------------------------
+
+public long maxTime() { return Long.MAX_VALUE >> pbits; }
+
+//--------------------------------------------------------------------------
+
+public long maxPriority() { return (1L << pbits)-1; }
+
+//--------------------------------------------------------------------------
+
+/** 
+ *  Prints the time values contained in the heap.
+ */
+public String toString()
+{
+       StringBuffer buffer = new StringBuffer();
+       buffer.append("[Size: " + size + " Times: ");
+       for (int i=1; i <= size; i++) {
+               buffer.append(getTime(i)+",");
+       }
+       buffer.append("]");
+       return buffer.toString();
+}
+
+
+//--------------------------------------------------------------------------
+// Private methods
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+private void minHeapify(int index) 
+{
+       // The time to be placed of the current node
+       long time = getTime(index);  
+       // Left, right children of the current index
+       int l,r; 
+       // Their associated time
+       long lt, rt;
+       // The minimum time between val, lt, rt
+       long mintime;
+       // The index of the mininum time
+       int minindex = index; 
+       do {
+               index = minindex;
+               mintime = time;
+               l = index << 1;
+               r = l + 1;
+               if (l <= size && (lt = getTime(l)) < mintime) {
+                       minindex = l;
+                       mintime = lt;
+               }
+               if (r <= size && (rt = getTime(r)) < mintime) {
+                       minindex = r;
+                       mintime = rt;
+               }
+               if (minindex != index) {
+                       swap(minindex, index);
+               }
+       } while (minindex != index);
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+private void swap(int i1, int i2) {
+       
+       i1--;
+       i2--;
+       
+       Object te = events[i1];
+       events[i1] = events[i2];
+       events[i2] = te;
+       
+       long tt = times[i1];
+       times[i1] = times[i2];
+       times[i2] = tt;
+       
+       Node tn = nodes[i1];
+       nodes[i1] = nodes[i2];
+       nodes[i2] = tn;
+
+       byte tp = pids[i1];
+       pids[i1] = pids[i2];
+       pids[i2] = tp;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+private long getTime(int index) {
+       /* Compute first and second index, and return the value */
+       index--;
+       return times[index];
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+private void put(int index, long time, Object event, Node node, byte pid) {
+       
+       index--;
+       if (index >= events.length) {
+               doubleCapacity();
+       }
+       events[index] = event;
+       times[index] = time;
+       nodes[index] = node;
+       pids[index] = pid;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+private void doubleCapacity() {
+       int oldsize = events.length;
+       int newsize = oldsize*2;
+       Object[] te = new Object[newsize];
+       System.arraycopy(events, 0, te, 0, oldsize);
+       events = te;
+       long[] tt = new long[newsize];
+       System.arraycopy(times, 0, tt, 0, oldsize);
+       times = tt;
+       Node[] tn = new Node[newsize];
+       System.arraycopy(nodes, 0, tn, 0, oldsize);
+       nodes = tn;
+       byte[] tp = new byte[newsize];
+       System.arraycopy(pids, 0, tp, 0, oldsize);
+       pids = tp;
+}
+
+//--------------------------------------------------------------------------
+// Testing
+//--------------------------------------------------------------------------
+
+/*
+public static void main(String[] args) {
+       Random random = new Random();
+       Heap heap = new Heap();
+       int rep = 1000000;
+       if( args.length > 0 ) rep = Integer.parseInt(args[0]);
+       int[] values1 = new int[rep];
+       long[] values2 = new long[rep];
+       for (int i = 0; i < rep; i++) {
+               values1[i] = random.nextInt(1000000000); 
+       }
+       
+       long time1 = System.currentTimeMillis();
+       for (int i = 0; i < rep; i++) {
+               heap.add(values1[i], null, null, (byte) 1);
+       }
+       long time2 = System.currentTimeMillis();
+       System.out.println("Inserting: " + (time2-time1));
+       
+       time1 = System.currentTimeMillis();
+       for (int i = 0; i < rep; i++) {
+               values2[i] = heap.removeFirst().time;
+       }
+       time2 = System.currentTimeMillis();
+       System.out.println("Removing: " + (time2-time1));
+       
+       Arrays.sort(values1);
+       for (int i=0; i<rep; i++) {
+               if (values1[i] != values2[i])
+                       System.out.print("+");
+       }
+}
+*/
+
+} // END Heap
diff --git a/contrib/psg/src/peersim/edsim/NextCycleEvent.java b/contrib/psg/src/peersim/edsim/NextCycleEvent.java
new file mode 100644 (file)
index 0000000..18de9d5
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.*;
+import peersim.cdsim.CDProtocol;
+
+/**
+ * This class is used to wrap a {@link CDProtocol} instance into an event so
+ * that it can be used in the event based simulation engine. This class is
+ * responsible for calling {@link CDProtocol#nextCycle} and also to schedule the
+ * consecutive cycle. In the configuration of an event driven simulation
+ * {@link CDProtocol}s can be configured using {@link CDScheduler}, which places
+ * appropriate instances of this events in the queue.
+ *
+ * <p>
+ * Note that reimplementing method {@link #nextDelay} of this class allows for
+ * arbitrary scheduling, including adaptively changing or irregular cycle
+ * lengths, etc.
+ *
+ * @see CDScheduler
+ * @see CDProtocol
+ */
+public class NextCycleEvent implements Cloneable {
+
+       // =============================== initialization ======================
+       // =====================================================================
+
+       /**
+        * Reads configuration to initialize the object. Extending classes should
+        * have a constructor with the same signature, often as simple as
+        * <code>super(n)</code>.
+        */
+       public NextCycleEvent(String n) {
+       }
+
+       // --------------------------------------------------------------------
+
+       /**
+        * Returns a clone of the object. Overriding this method is necessary and
+        * typically is as simple as <code>return super.clone()</code>. In general,
+        * always use <code>super.clone()</code> to obtain the object to be returned
+        * on which you can perform optional deep cloning operations (arrays, etc).
+        */
+       public Object clone() throws CloneNotSupportedException {
+
+               return super.clone();
+       }
+
+       // ========================== methods ==================================
+       // =====================================================================
+
+       /**
+        * Executes the nextCycle method of the protocol, and schedules the next
+        * call using the delay returned by {@link #nextDelay}. If the next
+        * execution time as defined by the delay is outside of the valid times as
+        * defined by {@link CDScheduler#sch}, then the next event is not scheduled.
+        * Note that this means that this protocol will no longer be scheduled
+        * because the next event after the next event is scheduled by the next
+        * event.
+        */
+       public final void execute() {
+
+               int pid = CommonState.getPid();
+               Node node = CommonState.getNode();
+               CDProtocol cdp = (CDProtocol) node.getProtocol(pid);
+               cdp.nextCycle(node, pid);
+               long delay = nextDelay(CDScheduler.sch[pid].step);
+
+               if (CommonState.getTime() + delay < CDScheduler.sch[pid].until)
+                       EDSimulator.add(delay, this, node, pid);
+       }
+
+       // --------------------------------------------------------------------
+
+       /**
+        * Calculates the delay until the next execution of the protocol. This
+        * default implementation returns a constant delay equal to the step
+        * parameter (cycle length in this case) of the schedule of this event (as
+        * set in the config file).
+        */
+       protected long nextDelay(long step) {
+
+               return step;
+       }
+
+}
diff --git a/contrib/psg/src/peersim/edsim/PriorityQ.java b/contrib/psg/src/peersim/edsim/PriorityQ.java
new file mode 100644 (file)
index 0000000..5525768
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c)2008 The Peersim Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.Node;
+
+/**
+ * The interface to be implemented by the event queue of the evend based
+ * engine. An implementation must also provide the standard cosntructor
+ * required by any peersim components: one that takes a String argument,
+ * the component name in the configuration.
+ */
+public interface PriorityQ {
+
+
+/**
+ * Returns the current number of events in the queue.
+ */
+public int size();
+
+/**
+ * Add a new event, to be scheduled at the specified time. If there are other
+ * events scheduled at the same time, then the time of execution if this event
+ * relative to the other events is unspecified.
+ * 
+ * @param time The time at which this event should be scheduled. It is
+ * guaranteed to be non-negative (so no extra checks are needed)
+ * @param event the object describing the event
+ * @param node the node at which the event has to be delivered
+ * @param pid the protocol that handles the event
+ */
+public void add(long time, Object event, Node node, byte pid);
+
+/**
+ * Add a new event, to be scheduled at the specified time, specifying also
+ * the priority of the event, should there be other events scheduled at the
+ * same time. If both time and priority is the same for an event, then the
+ * scheduling order is unspecified.
+ * 
+ * @param time The time at which this event should be scheduled. It is
+ * guaranteed to be non-negative (so no extra checks are needed)
+ * @param event the object describing the event
+ * @param node the node at which the event has to be delivered
+ * @param pid the protocol that handles the event
+ * @param priority if for two events the "time" value is the same, this
+ * value should be used to order them. Lower value means higher priority.
+ * Like with time, non-negativity as assumed.
+ */
+public void add(long time, Object event, Node node, byte pid, long priority);
+
+/**
+ * Removes the first event in the heap and returns it.
+ * The returned object is not guaranteed to be a freshly generated object,
+ * that is, we allow for an implementation that keeps one copy of an event
+ * object and always returns a reference to that copy.
+ * @return first event or null if size is zero
+ */
+public Event removeFirst();
+
+/**
+* Maximal value of time this interpretation can represent.
+*/
+public long maxTime();
+
+/**
+* Maximal value of priority this interpretation can deal with. That is,
+* the number of different priority levels is <tt>maxPriority()+1</tt> because
+* 0 is also a valid level.
+* @see #add(long,Object,Node,byte,long)
+*/
+public long maxPriority();
+
+/**
+ * Return type of {@link #removeFirst()}.
+ */
+public class Event
+{
+       public Object event;
+       public long time;
+       public Node node;
+       public byte pid;
+       public String toString() {
+               return event+" to node "+node+"prot "+pid+"at "+time; }
+}
+
+}
diff --git a/contrib/psg/src/peersim/edsim/RandNextCycle.java b/contrib/psg/src/peersim/edsim/RandNextCycle.java
new file mode 100644 (file)
index 0000000..b74a4f4
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.*;
+
+
+/**
+* Implements random delay between calling the nextCycle method of the protocol.
+* @see #nextDelay
+*/
+public class RandNextCycle extends NextCycleEvent {
+
+
+// =============================== initialization ======================
+// =====================================================================
+
+
+/**
+* Calls super constructor.
+*/
+public RandNextCycle(String n) { super(n); }
+
+// --------------------------------------------------------------------
+
+/**
+* Calls super.clone().
+*/
+public Object clone() throws CloneNotSupportedException {
+       
+       return super.clone();
+}
+
+
+// ========================== methods ==================================
+// =====================================================================
+
+
+/**
+* Returns a random delay with uniform distribution between 1 (inclusive) and
+* 2*<code>step</code> (exclusive)
+* (expected value is therefore <code>step</code>).
+*/
+protected long nextDelay(long step) {
+       
+       return 1+CommonState.r.nextLong((step<<1)-1);
+}
+
+
+}
+
+
diff --git a/contrib/psg/src/peersim/edsim/RegRandNextCycle.java b/contrib/psg/src/peersim/edsim/RegRandNextCycle.java
new file mode 100644 (file)
index 0000000..dbc5edb
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.*;
+
+
+/**
+* Implements a random delay, but making sure there is exactly one call in each
+* consecutive <code>step</code> time units.
+*/
+public class RegRandNextCycle extends NextCycleEvent {
+
+// ============================== fields ==============================
+// ====================================================================
+
+/**
+* Indicates the start of the next cycle for a particular protocol
+* instance. If negative it means it has not been initialized yet.
+*/
+private long nextCycleStart = -1;
+
+// =============================== initialization ======================
+// =====================================================================
+
+
+/**
+* Calls super constructor.
+*/
+public RegRandNextCycle(String n) {
+
+       super(n);
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Calls super.clone().
+*/
+public Object clone() throws CloneNotSupportedException {
+       
+       return super.clone();
+}
+
+
+// ========================== methods ==================================
+// =====================================================================
+
+
+/**
+* Returns a random delay but making sure there is exactly one invocation in each
+* consecutive interval of length <code>step</code>. The beginning of these
+* intervals is defined by the first invocation which is in turn defined by
+* {@link CDScheduler} that initiates the protocol in question.
+*/
+protected long nextDelay(long step) {
+       
+       // at this point nextCycleStart points to the start of the next cycle
+       // (the cycle after the one in which this execution is taking place)
+       // (note that the start of the cycle is included in the cycle)
+       
+       final long now = CommonState.getTime();
+       if(nextCycleStart<0)
+       {
+               // not initialized
+               nextCycleStart=now+step;
+       }
+       
+       // to be on the safe side, we do the next while loop.
+       // although currently it never executes
+       while(nextCycleStart<=now) nextCycleStart+=step;
+       
+       // we increment nextCycleStart to point to the start of the cycle
+       // after the next cycle
+       nextCycleStart+=step;
+       
+       return nextCycleStart-now-CommonState.r.nextLong(step)-1;
+}
+
+}
+
+
diff --git a/contrib/psg/src/peersim/edsim/edsim_jsp.xmi b/contrib/psg/src/peersim/edsim/edsim_jsp.xmi
new file mode 100644 (file)
index 0000000..5fba52d
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="ASCII"?>
+<jsp:Model xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:jsp="http://www.eclipse.org/MoDisco/JSP/0.1.incubation/jsp"/>
diff --git a/contrib/psg/src/peersim/edsim/edsim_kdm.xmi b/contrib/psg/src/peersim/edsim/edsim_kdm.xmi
new file mode 100644 (file)
index 0000000..db34498
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="ASCII"?>
+<kdm:Segment xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:kdm="http://www.eclipse.org/MoDisco/kdm/kdm" xmlns:source="http://www.eclipse.org/MoDisco/kdm/source">
+  <model xsi:type="source:InventoryModel" name="edsim">
+    <inventoryElement xsi:type="source:Directory" name="edsim" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim">
+      <inventoryElement xsi:type="source:SourceFile" name="RandNextCycle.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/RandNextCycle.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="RegRandNextCycle.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/RegRandNextCycle.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="Heap.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/Heap.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="ControlEvent.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/ControlEvent.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="EDSimulator.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/EDSimulator.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="CDScheduler.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/CDScheduler.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="PriorityQ.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/PriorityQ.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="NextCycleEvent.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/NextCycleEvent.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="EDProtocol.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/EDProtocol.java"/>
+    </inventoryElement>
+  </model>
+</kdm:Segment>
diff --git a/contrib/psg/src/peersim/graph/BitMatrixGraph.java b/contrib/psg/src/peersim/graph/BitMatrixGraph.java
new file mode 100644 (file)
index 0000000..7e88fec
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.graph;
+
+import java.util.*;
+
+/**
+* This class implements a graph which uses a bitmatrix as inner representation
+* of edges.
+*/
+public class BitMatrixGraph implements Graph {
+
+
+// ====================== private fileds ========================
+// ==============================================================
+
+private final List<BitSet> sets;
+
+private final boolean directed;
+
+// ====================== public constructors ===================
+// ==============================================================
+
+
+/**
+* Constructs a directed graph with the given number of nodes.
+* The graph has no edges initially. The graph is directed.
+* @param n size of graph
+*/
+public BitMatrixGraph( int n ) {
+
+       this(n,true);
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Constructs an graph with the given number of nodes.
+* The graph has no edges initially.
+* @param n size of graph
+* @param directed if true graph is directed
+*/
+public BitMatrixGraph( int n, boolean directed ) {
+
+       sets = new ArrayList<BitSet>(n);
+       for(int i=0; i<n; ++i) sets.add(new BitSet());
+       this.directed = directed;
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+       
+       return sets.get(i).get(j);
+}
+
+// ---------------------------------------------------------------
+
+public Collection<Integer> getNeighbours(int i) {
+       
+       Set<Integer> result = new HashSet<Integer>();
+       BitSet neighb = sets.get(i);
+       final int max = size();
+       for(int j=0; j<max; ++j)
+       {
+               if( neighb.get(j) ) result.add(j);
+       }
+
+       return Collections.unmodifiableCollection(result);
+}
+
+// ---------------------------------------------------------------
+
+/** Returns null always */
+public Object getNode(int i) { return null; }
+       
+// ---------------------------------------------------------------
+
+/**
+* Returns null always. 
+*/
+public Object getEdge(int i, int j) { return null; }
+
+// ---------------------------------------------------------------
+
+public int size() { return sets.size(); }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return directed; }
+
+// --------------------------------------------------------------------
+
+public boolean setEdge(int i, int j) {
+
+       if( i > size() || j > size() || i<0 || j<0 ) throw new
+               IndexOutOfBoundsException();
+
+       BitSet neighb = sets.get(i);
+       boolean old = neighb.get(j);
+       neighb.set(j);
+       
+       if( !old && !directed )
+       {
+               neighb = sets.get(j);
+               neighb.set(i);
+       }
+       
+       return !old;
+}
+
+// --------------------------------------------------------------------
+
+public boolean clearEdge(int i, int j) {
+
+       if( i > size() || j > size() || i<0 || j<0 ) throw new
+               IndexOutOfBoundsException();
+
+       BitSet neighb = sets.get(i);
+       boolean old = neighb.get(j);
+       neighb.clear(j);
+       
+       if( old && !directed )
+       {
+               neighb = sets.get(i);
+               neighb.clear(j);
+       }
+       
+       return old;
+}
+
+// --------------------------------------------------------------------
+
+public int degree(int i) {
+
+       BitSet neighb = sets.get(i);
+       return neighb.cardinality(); // only from jdk 1.4
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/graph/ConstUndirGraph.java b/contrib/psg/src/peersim/graph/ConstUndirGraph.java
new file mode 100644 (file)
index 0000000..3aac06f
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.graph;
+
+import java.util.*;
+
+/**
+* This class is an adaptor making any Graph an undirected graph
+* by making its edges bidirectional. The graph to be made undirected
+* is passed to the constructor. Only the reference is stored.
+* However, at construction time the incoming edges are stored
+* for each node, so if the graph
+* passed to the constructor changes over time then
+* methods {@link #getNeighbours(int)} and {@link #degree(int)}
+* become inconsistent (but only those).
+* The upside of this inconvenience is that {@link #getNeighbours} will have
+* constant time complexity.
+* @see UndirectedGraph
+*/
+public class ConstUndirGraph implements Graph {
+
+
+// ====================== private fileds ========================
+// ==============================================================
+
+
+protected final Graph g;
+
+protected final List<Integer>[] in;
+
+// ====================== public constructors ===================
+// ==============================================================
+
+/**
+* Initialization based on given graph. Stores the graph and if necessary
+* (if the graph is directed) searches for the incoming edges and stores
+* them too. The given graph is stored by reference (not cloned) so it should
+* not be modified while this object is in use.
+*/
+public ConstUndirGraph( Graph g ) {
+
+       this.g = g;
+       if( !g.directed() )
+       {
+               in = null;
+       }
+       else
+       {
+               in = new List[g.size()];
+       }
+       
+       initGraph();
+}
+       
+// --------------------------------------------------------------
+
+/** Finds and stores incoming edges */
+protected void initGraph() {
+
+       final int max = g.size();
+       for(int i=0; i<max; ++i) in[i] = new ArrayList<Integer>();
+       for(int i=0; i<max; ++i)
+       {
+               for(Integer j:g.getNeighbours(i))
+               {
+                       if( ! g.isEdge(j,i) ) in[j].add(i);
+               }
+       }
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+       
+       return g.isEdge(i,j) || g.isEdge(j,i);
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Uses sets as collection so does not support multiple edges now, even if
+* the underlying directed graph does.
+*/
+public Collection<Integer> getNeighbours(int i) {
+       
+       List<Integer> result = new ArrayList<Integer>();
+       result.addAll(g.getNeighbours(i));
+       if( in != null ) result.addAll(in[i]);
+       return Collections.unmodifiableCollection(result);
+}
+
+// ---------------------------------------------------------------
+
+/** Returns the node from the underlying graph */
+public Object getNode(int i) { return g.getNode(i); }
+       
+// ---------------------------------------------------------------
+
+/**
+* If there is an (i,j) edge, returns that, otherwise if there is a (j,i)
+* edge, returns that, otherwise returns null.
+*/
+public Object getEdge(int i, int j) {
+       
+       if( g.isEdge(i,j) ) return g.getEdge(i,j);
+       if( g.isEdge(j,i) ) return g.getEdge(j,i);
+       return null;
+}
+
+// ---------------------------------------------------------------
+
+public int size() { return g.size(); }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return false; }
+
+// --------------------------------------------------------------------
+
+/** not supported */
+public boolean setEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+/** not supported */
+public boolean clearEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+public int degree(int i) { return g.degree(i)+(in==null?0:in[i].size()); }
+
+// ---------------------------------------------------------------
+/*
+public static void main( String[] args ) {
+
+       Graph net = new BitMatrixGraph(20);
+       GraphFactory.wireKOut(net,5,new Random());
+       ConstUndirGraph ug = new ConstUndirGraph(net);
+       for(int i=0; i<net.size(); ++i)
+               System.err.println(
+                       i+" "+net.getNeighbours(i)+" "+net.degree(i));
+       System.err.println("============");
+       for(int i=0; i<ug.size(); ++i)
+               System.err.println(i+" "+ug.getNeighbours(i)+" "+ug.degree(i));
+       System.err.println("============");
+       for(int i=0; i<ug.size(); ++i)
+               System.err.println(i+" "+ug.in[i]);
+       for(int i=0; i<ug.size(); ++i)
+       {
+               for(int j=0; j<ug.size(); ++j)
+                       System.err.print(ug.isEdge(i,j)?"W ":"+ ");
+               System.err.println();
+       }
+
+       GraphIO.writeUCINET_DL(net,System.out);
+       GraphIO.writeUCINET_DL(ug,System.out);
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/graph/FastUndirGraph.java b/contrib/psg/src/peersim/graph/FastUndirGraph.java
new file mode 100644 (file)
index 0000000..9f5de5e
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * Created on Jan 30, 2005 by Spyros Voulgaris
+ *
+ */
+package peersim.graph;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+
+/**
+* Speeds up {@link ConstUndirGraph#isEdge} by storing the links in an
+* adjacency matrix (in fact in a triangle).
+* Its memory consumption is huge but it's much faster if the isEdge method
+* of the original underlying graph is slow.
+*/
+public class FastUndirGraph extends ConstUndirGraph
+{
+
+private BitSet[] triangle;
+
+
+// ======================= initializarion ==========================
+// =================================================================
+
+
+/** Calls super constructor */
+public FastUndirGraph(Graph graph)
+{
+       super(graph);
+}
+
+// -----------------------------------------------------------------
+
+protected void initGraph()
+{
+       final int max = g.size();
+       triangle = new BitSet[max];
+       for (int i=0; i<max; ++i)
+       {
+               in[i] = new ArrayList<Integer>();
+               triangle[i] = new BitSet(i);
+       }
+
+       for(int i=0; i<max; ++i)
+       {
+               for(Integer out:g.getNeighbours(i))
+               {
+                       int j=out.intValue();
+                       if( ! g.isEdge(j,i) )
+                               in[j].add(i);
+                       // But always add the link to the triangle
+                       if (i>j) // make sure i>j
+                               triangle[i].set(j);
+                       else
+                               triangle[j].set(i);
+               }
+       }
+}
+
+
+// ============================ Graph functions ====================
+// =================================================================
+
+
+public boolean isEdge(int i, int j)
+{
+       // make sure i>j
+       if (i<j)
+       {
+               int ii=i;
+               i=j;
+               j=ii;
+       }
+       return triangle[i].get(j);
+}
+}
+
diff --git a/contrib/psg/src/peersim/graph/Graph.java b/contrib/psg/src/peersim/graph/Graph.java
new file mode 100644 (file)
index 0000000..70a2142
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.graph;
+
+import java.util.Collection;
+
+/**
+* A general graph interface. It follows the following model:
+* the graph has n nodes which are indexed from 0 to n-1.
+* The parameters of operators refer to indices only.
+* Implementations might return objects that represent the
+* nodes or edges, although this is not required.
+*
+* Undirected graphs are modelled by the interface as directed graphs in which
+* every edge (i,j) has a corresponding reverse edge (j,i).
+*/
+public interface Graph {
+
+       /**
+       * Returns true if there is a directed edge between node i
+       * and node j.
+       */
+       boolean isEdge(int i, int j);
+
+       /**
+       * Returns a collection view to all outgoing edges from
+       * i. The collection should ideally be unmodifiable.
+       * In any case, modifying the returned collection is not safe and
+       * may result in unspecified behavior.
+       */
+       Collection<Integer> getNeighbours(int i);
+
+       /**
+       * Returns the node object associated with the index. Optional
+       * operation.
+       */
+       Object getNode(int i);
+       
+       /**
+       * Returns the edge object associated with the index. Optional
+       * operation.
+       */
+       Object getEdge(int i, int j);
+
+       /**
+       * The number of nodes in the graph.
+       */
+       int size();
+
+       /**
+       * Returns true if the graph is directed otherwise false.
+       */
+       boolean directed();
+
+       /**
+       * Sets given edge, returns true if it did not exist before.
+       * If the graph is
+       * undirected, sets the edge (j,i) as well. Optional operation.
+       */
+       public boolean setEdge(int i, int j);
+
+       /**
+       * Removes given edge, returns true if it existed before. If the graph is
+       * undirected, removes the edge (j,i) as well. Optional operation.
+       */
+       public boolean clearEdge(int i, int j);
+
+       /**
+       * Returns the degree of the given node. If the graph is directed,
+       * returns out degree.
+       */
+       public int degree(int i);
+}
diff --git a/contrib/psg/src/peersim/graph/GraphAlgorithms.java b/contrib/psg/src/peersim/graph/GraphAlgorithms.java
new file mode 100644 (file)
index 0000000..6bbb351
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.graph;
+
+import java.util.*;
+
+/**
+* Implements graph algorithms. The current implementation is NOT thread
+* safe. Some algorithms are not static, many times the result of an
+* algorithm can be read from non-static fields.
+*/
+public class GraphAlgorithms {
+
+// =================== public fields ==================================
+// ====================================================================
+
+/** output of some algorithms is passed here */
+public int[] root = null;
+private Stack<Integer> stack = new Stack<Integer>();
+private int counter=0;
+
+private Graph g=null;
+
+public final static int WHITE=0;
+public final static int GREY=1;
+public final static int BLACK=2;
+
+/** output of some algorithms is passed here */
+public int[] color = null;
+
+/** output of some algorithms is passed here */
+public Set<Integer> cluster = null;
+
+/** output of some algorithms is passed here */
+public int[] d = null;
+
+// =================== private methods ================================
+// ====================================================================
+
+
+/**
+* Collects nodes accessible from node "from" using depth-first search.
+* Works on the array {@link #color} which must be of the same length as
+* the size of the graph, and must contain values according to the
+* following semantics: 
+* WHITE (0): not seen yet, GREY (1): currently worked upon. BLACK
+* (other than 0 or 1): finished.
+* If a negative color is met, it is saved in the {@link #cluster} set
+* and is treated as black. This can be used to check if the currently
+* visited cluster is weakly connected to another cluster.
+* On exit no nodes are GREY.
+* The result is the modified array {@link #color} and the modified set
+* {@link #cluster}.
+*/
+private void dfs( int from ) {
+
+       color[from]=GREY;
+
+       for(int j:g.getNeighbours(from))
+       {
+               if( color[j]==WHITE )
+               {
+                       dfs(j);
+               }
+               else
+               {
+                       if( color[j]<0 ) cluster.add(color[j]);
+               }
+       }
+
+       color[from]=BLACK;
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Collects nodes accessible from node "from" using breadth-first search.
+* Its parameters and side-effects are identical to those of dfs.
+* In addition, it stores the shortest distances from "from" in {@link #d},
+* if it is not null. On return, <code>d[i]</code> contains the length of
+* the shortest path from "from" to "i", if such a path exists, or it is
+* unchanged (ie the original value of <code>d[i]</code> is kept,
+* whatever that was.
+* <code>d</code> must either be long enough or null.
+*/
+private void bfs( int from ) {
+
+       List<Integer> q = new LinkedList<Integer>();
+       int u, du;
+       
+       q.add(from);
+       q.add(0);
+       if( d != null ) d[from] = 0;
+
+       color[from]=GREY;
+
+       while( ! q.isEmpty() )
+       {
+               u = q.remove(0).intValue();
+               du = q.remove(0).intValue();
+               
+               for(int j:g.getNeighbours(u))
+               {
+                       if( color[j]==WHITE )
+                       {
+                               color[j]=GREY;
+                               
+                               q.add(j);
+                               q.add(du+1);
+                               if( d != null ) d[j] = du+1;
+                       }
+                       else
+                       {
+                               if( color[j]<0 )
+                                       cluster.add(color[j]);
+                       }
+               }
+               color[u]=BLACK;
+       }
+}
+
+// --------------------------------------------------------------------
+
+/** The recursive part of the Tarjan algorithm. */
+private void tarjanVisit(int i) {
+
+       color[i]=counter++;
+       root[i]=i;
+       stack.push(i);
+       
+       for(int j:g.getNeighbours(i))
+       {
+               if( color[j]==WHITE )
+               {
+                       tarjanVisit(j);
+               }
+               if( color[j]>0 && color[root[j]]<color[root[i]] )
+               // inComponent is false and have to update root
+               {
+                       root[i]=root[j];
+               }
+       }
+
+       int j;
+       if(root[i]==i) //this node is the root of its cluster
+       {
+               do
+               {
+                       j=stack.pop();
+                       color[j]=-color[j];
+                       root[j]=i;
+               }
+               while(j!=i);
+       }
+}
+
+// =================== public methods ================================
+// ====================================================================
+
+/** Returns the weakly connected cluster indexes with size as a value.
+* Cluster membership can be seen from the content of the array {@link #color};
+* each node has the cluster index as color. The cluster indexes carry no
+* information; we guarantee only that different clusters have different indexes.
+*/
+public Map weaklyConnectedClusters( Graph g ) {
+
+       this.g=g;
+       if( cluster == null ) cluster = new HashSet<Integer>();
+       if( color==null || color.length<g.size() ) color = new int[g.size()];
+
+       // cluster numbers are negative integers
+       int i, j, actCluster=0;
+       for(i=0; i<g.size(); ++i) color[i]=WHITE;
+       for(i=0; i<g.size(); ++i)
+       {
+               if( color[i]==WHITE )
+               {
+                       cluster.clear();
+                       bfs(i); // dfs is recursive, for large graphs not ok
+                       --actCluster;
+                       for(j=0; j<g.size(); ++j)
+                       {
+                               if( color[j] == BLACK ||
+                                               cluster.contains(color[j]) )
+                                       color[j] = actCluster;
+                       }
+               }
+       }
+
+       Hashtable<Integer,Integer> ht = new Hashtable<Integer,Integer>();
+       for(j=0; j<g.size(); ++j)
+       {
+               Integer num = ht.get(color[j]);
+               if( num == null ) ht.put(color[j],Integer.valueOf(1));
+               else ht.put(color[j],num+1);
+       }
+       
+       return ht;
+}
+
+// --------------------------------------------------------------------
+
+/**
+* In <code>{@link #d}[j]</code> returns the length of the shortest path between
+* i and j. The value -1 indicates that j is not accessible from i.
+*/
+public void dist( Graph g, int i ) {
+
+       this.g=g;
+       if( d==null || d.length<g.size() ) d = new int[g.size()];
+       if( color==null || color.length<g.size() ) color = new int[g.size()];
+       
+       for(int j=0; j<g.size(); ++j)
+       {
+               color[j]=WHITE;
+               d[j] = -1;
+       }
+       
+       bfs(i);
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Calculates the clustering coefficient for the given node in the given
+* graph. The clustering coefficient is the number of edges between
+* the neighbours of i divided by the number of possible edges.
+* If the graph is directed, an exception is thrown.
+* If the number of neighbours is 1, returns 1. For zero neighbours
+* returns NAN.
+* @throws IllegalArgumentException if g is directed
+*/
+public static double clustering( Graph g, int i ) {
+
+       if( g.directed() ) throw new IllegalArgumentException(
+               "graph is directed");
+               
+       Object[] n = g.getNeighbours(i).toArray();
+       
+       if( n.length==1 ) return 1.0;
+       
+       int edges = 0;
+       
+       for(int j=0; j<n.length; ++j)
+       for(int k=j+1; k<n.length; ++k)
+               if( g.isEdge((Integer)n[j],(Integer)n[k]) ) ++edges;
+
+       return ((edges*2.0)/n.length)/(n.length-1);
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Performs anti-entropy epidemic multicasting from node 0.
+* As a result the number of nodes that have been reached in cycle i
+* is put into <code>b[i]</code>.
+* The number of cycles performed is determined by <code>b.length</code>.
+* In each cycle each node contacts a random neighbour and exchanges
+* information. The simulation is generational: when a node contacts a neighbor
+* in cycle i, it sees their state as in cycle i-1, besides, all nodes update
+* their state at the same time point, synchronously.
+*/
+public static void multicast( Graph g, int[] b, Random r ) {
+
+       int c1[] = new int[g.size()];
+       int c2[] = new int[g.size()];
+       for(int i=0; i<c1.length; ++i) c2[i]=c1[i]=WHITE;
+       c2[0]=c1[0]=BLACK;
+       Collection<Integer> neighbours=null;
+       int black=1;
+       
+       int k=0;
+       for(; k<b.length || black<g.size(); ++k)
+       {
+               for(int i=0; i<c2.length; ++i)
+               {
+                       neighbours=g.getNeighbours(i);
+                       Iterator<Integer> it=neighbours.iterator();
+                       for(int j=r.nextInt(neighbours.size()); j>0; --j)
+                               it.next();
+                       int randn = it.next();
+                       
+                       // push pull exchane with random neighbour
+                       if( c1[i]==BLACK ) //c2[i] is black too
+                       {
+                               if(c2[randn]==WHITE) ++black;
+                               c2[randn]=BLACK;
+                       }
+                       else if( c1[randn]==BLACK )
+                       {
+                               if(c2[i]==WHITE) ++black;
+                               c2[i]=BLACK;
+                       }
+               }
+               System.arraycopy(c2,0,c1,0,c1.length);
+               b[k]=black;
+       }
+       
+       for(; k<b.length; ++k) b[k]=g.size();
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Performs flooding from given node.
+* As a result <code>b[i]</code> contains the number of nodes
+* reached in exactly i steps, and always <code>b[0]=1</code>.
+* If the maximal distance from k is lower than <code>b.length</code>,
+* then the remaining elements of b are zero.
+*/
+public void flooding( Graph g, int[] b, int k ) {
+
+       dist(g, k);
+
+       for(int i=0; i<b.length; ++i) b[i]=0;
+       for(int i=0; i<d.length; ++i)
+       {
+               if( d[i] >= 0 && d[i] < b.length ) b[d[i]]++;
+       }
+}
+
+// --------------------------------------------------------------------
+
+/** Returns the strongly connected cluster roots with size as a value.
+* Cluster membership can be seen from the content of the array {@link #root};
+* each node has the root of the strongly connected cluster it belongs to.
+* A word of caution: for large graphs that have a large diameter and that
+* are strongly connected (such as large rings) you can get stack overflow
+* because of the large depth of recursion.
+*/
+//XXX implement a non-recursive version ASAP!!!
+public Map tarjan( Graph g ) {
+       
+       this.g=g;
+       stack.clear();
+       if( root==null || root.length<g.size() ) root = new int[g.size()];
+       if( color==null || color.length<g.size() ) color = new int[g.size()];
+       for( int i=0; i<g.size(); ++i) color[i]=WHITE;
+       counter = 1;
+       
+       // color is WHITE (0): not visited
+       // not WHITE, positive (c>1): visited as the c-th node
+       // color is negative (c<1): inComponent true
+       for(int i=0; i<g.size(); ++i)
+       {
+               if( color[i]==WHITE ) tarjanVisit(i);
+       }
+       for( int i=0; i<g.size(); ++i) color[i]=0;
+       for( int i=0; i<g.size(); ++i) color[root[i]]++;
+       Hashtable<Integer,Integer> ht = new Hashtable<Integer,Integer>();
+       for(int j=0; j<g.size(); ++j)
+       {
+               if(color[j]>0)
+               {
+                       ht.put(j,color[j]);
+               }
+       }
+       
+       return ht;
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/graph/GraphFactory.java b/contrib/psg/src/peersim/graph/GraphFactory.java
new file mode 100644 (file)
index 0000000..81857cc
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.graph;
+
+import java.util.*;
+
+/**
+* Contains static methods for wiring certain kinds of graphs. The general
+* contract of all methods is that they accept any graph and add edges
+* as specified in the documentation.
+*/
+public class GraphFactory {
+
+/** Disable instance construction */
+private GraphFactory() {}
+
+// ===================== public static methods ======================
+// ==================================================================
+
+/**
+* Wires a ring lattice.
+* The added connections are defined as follows. If k is even, links to
+* i-k/2, i-k/2+1, ..., i+k/2 are added (but not to i), thus adding an
+* equal number of predecessors and successors.
+* If k is odd, then we add one more successors than predecessors.
+* For example, for k=4: 2 predecessors, 2 successors.
+* For k=5: 2 predecessors, 3 successors.
+* For k=1: each node is linked only to its successor.
+* All values are understood mod n to make the lattice circular, where n is the
+* number of nodes in g.
+* @param g the graph to be wired
+* @param k lattice parameter
+* @return returns g for convenience
+*/
+public static Graph wireRingLattice(Graph g, int k) {
+       
+       final int n = g.size();
+
+       int pred = k/2;
+       int succ = k-pred;
+
+       for(int i=0; i<n; ++i)
+       for(int j=-pred; j<=succ; ++j)
+       {
+               if( j==0 ) continue;
+               final int v = (i+j+n)%n;
+               g.setEdge(i,v);
+       }
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Watts-Strogatz model. A bit modified though: by default assumes a directed
+* graph. This means that directed
+* links are re-wired, and the undirected edges in the original (undirected)
+* lattice are modeled
+* by double directed links pointing in opposite directions. Rewiring is done
+* with replacement, so the possibility of wiring two links to the same target
+* is positive (though very small).
+* <p>
+* Note that it is possible to pass an undirected graph as a parameter. In that
+* case the output is the directed graph produced by the method, converted to
+* an undirected graph by dropping directionality of the edges. This graph is
+* still not from the original undirected WS model though.
+* @param g the graph to be wired
+* @param k lattice parameter: this is the out-degree of a node in the
+* ring lattice before rewiring
+* @param p the probability of rewiring each 
+* @param r source of randomness
+* @return returns g for convenience
+*/
+public static Graph wireWS( Graph g, int k, double p, Random r ) {
+//XXX unintuitive to call it WS due to the slight mods
+       final int n = g.size();
+       for(int i=0; i<n; ++i)
+       for(int j=-k/2; j<=k/2; ++j)
+       {
+               if( j==0 ) continue;
+               int newedge = (i+j+n)%n;
+               if( r.nextDouble() < p )
+               {
+                       newedge = r.nextInt(n-1);
+                       if( newedge >= i ) newedge++; // random _other_ node
+               }
+               g.setEdge(i,newedge);
+       }
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Random graph. Generates randomly k directed edges out of each node.
+* The neighbors
+* (edge targets) are chosen randomly without replacement from the nodes of the
+* graph other than the source node (i.e. no loop edge is added).
+* If k is larger than N-1 (where N is the number of nodes) then k is set to
+* be N-1 and a complete graph is returned.
+* @param g the graph to be wired
+* @param k samples to be drawn for each node
+* @param r source of randomness
+* @return returns g for convenience
+*/
+public static Graph wireKOut( Graph g, int k, Random r ) {
+
+       final int n = g.size();
+       if( n < 2 ) return g;
+       if( n <= k ) k=n-1;
+       int[] nodes = new int[n];
+       for(int i=0; i<nodes.length; ++i) nodes[i]=i;
+       for(int i=0; i<n; ++i)
+       {
+               int j=0;
+               while(j<k)
+               {
+                       int newedge = j+r.nextInt(n-j);
+                       int tmp = nodes[j];
+                       nodes[j] = nodes[newedge];
+                       nodes[newedge] = tmp;
+                       if( nodes[j] != i )
+                       {
+                               g.setEdge(i,nodes[j]);
+                               j++;
+                       }
+               }
+       }
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* A sink star.
+* Wires a sink star topology adding a link to 0 from all other nodes.
+* @param g the graph to be wired
+* @return returns g for convenience
+*/
+public static Graph wireStar( Graph g ) {
+
+       final int n = g.size();
+       for(int i=1; i<n; ++i) g.setEdge(i,0);
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* A regular rooted tree.
+* Wires a regular rooted tree. The root is 0, it has links to 1,...,k.
+* In general, node i has links to i*k+1,...,i*k+k.
+* @param g the graph to be wired
+* @param k the number of outgoing links of nodes in the tree (except
+* leaves that have zero out-links, and exactly one node that might have
+* less than k).
+* @return returns g for convenience
+*/
+public static Graph wireRegRootedTree( Graph g, int k ) {
+
+       if( k==0 ) return g;
+       final int n = g.size();
+       int i=0; // node we wire
+       int j=1; // next free node to link to
+       while(j<n)
+       {
+               for(int l=0; l<k && j<n; ++l,++j) g.setEdge(i,j);
+               ++i;
+       }
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* A hypercube.
+* Wires a hypercube.
+* For a node i the following links are added: i xor 2^0, i xor 2^1, etc.
+* this define a log(graphsize) dimensional hypercube (if the log is an
+* integer).
+* @param g the graph to be wired
+* @return returns g for convenience
+*/
+public static Graph wireHypercube( Graph g ) {
+
+       final int n = g.size();
+       if(n<=1) return g;
+       final int highestone = Integer.highestOneBit(n-1); // not zero
+       for(int i=0; i<n; ++i)
+       {
+               int mask = highestone;
+               while(mask>0)
+               {
+                       int j = i^mask;
+                       if(j<n) g.setEdge(i,j);
+                       mask = mask >> 1;
+               }
+               
+       }
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* This contains the implementation of the Barabasi-Albert model
+* of growing scale free networks. The original model is described in
+* <a href="http://arxiv.org/abs/cond-mat/0106096">
+http://arxiv.org/abs/cond-mat/0106096</a>.
+* It also works if the graph is directed, in which case the model is a
+* variation of the BA model
+* described in <a href="http://arxiv.org/pdf/cond-mat/0408391">
+http://arxiv.org/pdf/cond-mat/0408391</a>. In both cases, the number of the
+* initial set of nodes is the same as the degree parameter, and no links are
+* added. The first added node is connected to all of the initial nodes,
+* and after that the BA model is used normally.
+* @param k the number of edges that are generated for each new node, also
+* the number of initial nodes (that have no edges).
+* @param r the randomness to be used
+* @return returns g for convenience
+*/
+public static Graph wireScaleFreeBA( Graph g, int k, Random r ) {
+
+       final int nodes = g.size();
+       if( nodes <= k ) return g;
+       
+       // edge i has ends (ends[2*i],ends[2*i+1])
+       int[] ends = new int[2*k*(nodes-k)];
+       
+       // Add initial edges from k to 0,1,...,k-1
+       for(int i=0; i < k; i++)
+       {
+               g.setEdge(k,i);
+               ends[2*i]=k;
+               ends[2*i+1]=i;
+       }
+       
+       int len = 2*k; // edges drawn so far is len/2
+       for(int i=k+1; i < nodes; i++) // over the remaining nodes
+       {
+               for (int j=0; j < k; j++) // over the new edges
+               {
+                       int target;
+                       do
+                       {
+                               target = ends[r.nextInt(len)]; 
+                               int m=0;
+                               while( m<j && ends[len+2*m+1]!=target) ++m;
+                               if(m==j) break;
+                               // we don't check in the graph because
+                               // this wire method should accept graphs
+                               // that already have edges.
+                       }
+                       while(true);
+                       g.setEdge(i,target);
+                       ends[len+2*j]=i;
+                       ends[len+2*j+1]=target;
+               }
+               len += 2*k;
+       }
+
+       return g;
+}
+
+// -------------------------------------------------------------------
+/*
+public static void main(String[] pars) {
+       
+       int n = Integer.parseInt(pars[0]);
+       //int k = Integer.parseInt(pars[1]);
+       Graph g = new BitMatrixGraph(n);
+       
+       //wireWS(g,20,.1,new Random());
+       //GraphIO.writeChaco(new UndirectedGraph(g),System.out);
+       
+       //wireScaleFreeBA(g,3,new Random());
+       //wireKOut(g,k,new Random());
+       //wireRegRootedTree(g,k);
+       wireHypercube(g);
+       GraphIO.writeNeighborList(g,System.out);
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/graph/GraphIO.java b/contrib/psg/src/peersim/graph/GraphIO.java
new file mode 100644 (file)
index 0000000..9d928d3
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.graph;
+
+import java.util.*;
+import java.io.*;
+
+/**
+* Implements static methods to load and write graphs.
+*/
+public class GraphIO {
+private GraphIO() {}
+
+
+// ================== public static methods =========================
+// ==================================================================
+
+
+/**
+* Prints graph in edge list format. Each line contains exactly two
+* node IDs separated by whitespace.
+*/
+public static void writeEdgeList( Graph g, PrintStream out ) {
+
+       for(int i=0; i<g.size(); ++i)
+       {
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.println(i+" "+it.next());
+               }
+       }
+}
+
+// ------------------------------------------------------------------
+
+/**
+* Prints graph in neighbor list format. Each line starts with the
+* id of a node followed by the ids of its neighbors separated by space.
+*/
+public static void writeNeighborList( Graph g, PrintStream out ) {
+
+       out.println("# "+g.size());
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               out.print(i+" ");
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.print(it.next()+" ");
+               }
+               out.println();
+       }
+}
+
+// ------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream in DOT format. Good for the graphviz package.
+*/
+public static void writeDOT( Graph g, PrintStream out ) {
+
+       out.println((g.directed()?"digraph":"graph")+" {");
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               Iterator<Integer> it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       final int j = it.next();
+                       if(g.directed())
+                               out.println(i+" -> "+j+";");
+                       else if( i<=j )
+                               out.println(i+" -- "+j+";");
+               }
+       }
+       
+       out.println("}");
+}
+
+// ------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream in GML format.
+*/
+public static void writeGML( Graph g, PrintStream out ) {
+
+       out.println("graph [ directed "+(g.directed()?"1":"0"));
+       
+       for(int i=0; i<g.size(); ++i)
+               out.println("node [ id "+i+" ]");
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.println(
+                               "edge [ source "+i+" target "+it.next()+" ]");
+               }
+       }
+       
+       out.println("]");
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream to be read by NETMETER. It should be ok also for Pajek.
+*/
+public static void writeNetmeter( Graph g, PrintStream out ) {
+
+       out.println("*Vertices "+g.size());
+       for(int i=0; i<g.size(); ++i)
+               out.println((i+1)+" \""+(i+1)+"\"");
+       
+       out.println("*Arcs");
+       for(int i=0; i<g.size(); ++i)
+       {
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.println((i+1)+" "+
+                               (((Integer)it.next()).intValue()+1)+" 1");
+               }
+       }
+       out.println("*Edges");
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream in UCINET DL nodelist format.
+*/
+public static void writeUCINET_DL( Graph g, PrintStream out ) {
+
+       out.println("DL\nN="+g.size()+"\nFORMAT=NODELIST\nDATA:");
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               out.print(" " + (i+1));
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.print(" "+(((Integer)it.next()).intValue()+1));
+               }
+               out.println();
+       }
+       out.println();
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream in UCINET DL matrix format.
+*/
+public static void writeUCINET_DLMatrix( Graph g, PrintStream out ) {
+
+       out.println("DL\nN="+g.size()+"\nDATA:");
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               BitSet bs = new BitSet(g.size());
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       bs.set( ((Integer)it.next()).intValue() );
+               }
+               for(int j=0; j<g.size(); ++j)
+               {
+                       out.print(bs.get(j)?" 1":" 0");
+               }
+               out.println();
+       }
+       out.println();
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream in Chaco format. We need to output the number of edges
+* so they have to be counted first which might not be very efficient.
+* Note that this format is designed for undirected graphs only.
+*/
+public static void writeChaco( Graph g, PrintStream out ) {
+
+       if( g.directed() ) System.err.println(
+               "warning: you're saving a directed graph in Chaco format");
+       
+       long edges = 0;
+       for(int i=0; i<g.size(); ++i) edges += g.getNeighbours(i).size();
+       
+       out.println( g.size() + " " + edges/2 );
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.print((((Integer)it.next()).intValue()+1)+" ");
+               }
+               out.println();
+       }
+       
+       out.println();
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Read a graph in newscast graph format.
+* The format depends on mode, the parameter.
+* The file begins with the three byte latin 1 coded "NCG" string followed
+* by the int MODE which is the
+* given parameter. The formats are the following as a function of mode:
+* <ul>
+* <li> 1: Begins with cacheSize in binary format (int), followed by the
+*     numberOfNodes (int), and then a continuous series of exactly
+*     numberOfNodes records, where a record describes a node's
+*     neighbours and their timestamps.
+*     A record is a series of exactly cacheSize (int,long) pairs where
+*     the int is the node id, and the long is the timestamp.
+*     Node id-s start from 1. Node id 0 means no node and used if the parent
+*     node has less that cacheSize nodes.</li>
+* </ul>
+* @param file Filename to read
+* @param direction If 0, the original directionality is preserved, if 1,
+* than each edge is reversed, if 2 then directionality is dropped and the
+* returned graph will be undirected.
+*/
+public static Graph readNewscastGraph( String file, int direction )
+throws IOException {
+       
+       NeighbourListGraph gr = new NeighbourListGraph( direction != 2 );
+       FileInputStream fis = new FileInputStream(file);
+       DataInputStream dis = new DataInputStream(fis);
+
+       dis.readByte();
+       dis.readByte();
+       dis.readByte();
+       
+       final int MODE = dis.readInt();
+       if( MODE != 1 ) throw new IOException("Unknown mode "+MODE);
+       
+       final int CACHESIZE = dis.readInt(); 
+       final int GRAPHSIZE = dis.readInt(); 
+       
+//System.out.println("header: "+MODE+" "+CACHESIZE+" "+GRAPHSIZE);
+       
+       for(int i=1; i<=GRAPHSIZE; ++i)
+       {
+               int iind = gr.addNode(i);
+               
+               for(int j=0; j<CACHESIZE; ++j)
+               {
+                       int a = dis.readInt();
+                       dis.readLong();
+                       
+                       int agentIndex = gr.addNode(a);
+                       if( direction == 0 ) gr.setEdge(iind,agentIndex);
+                       else gr.setEdge(agentIndex,iind);
+               }
+       }
+       
+       dis.close();
+
+       return gr;
+}
+
+
+}
+
diff --git a/contrib/psg/src/peersim/graph/NeighbourListGraph.java b/contrib/psg/src/peersim/graph/NeighbourListGraph.java
new file mode 100644 (file)
index 0000000..50b3c97
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.graph;
+
+import java.util.*;
+
+/**
+* Implements a graph which uses the neighbour list representation.
+* No multiple edges are allowed. The implementation also supports the
+* growing of the graph. This is very useful when the number of nodes is
+* not known in advance or when we construct a graph reading a file.
+*/
+public class NeighbourListGraph implements Graph, java.io.Serializable {
+
+// =================== private fields ============================
+// ===============================================================
+
+/** Contains the objects associated with the node indeces.*/
+private final ArrayList<Object> nodes;
+
+/**
+* Contains the indices of the nodes. The vector "nodes" contains this
+* information implicitly but this way we can find indexes in log time at
+* the cost of memory (node that the edge lists typically use much more memory
+* than this anyway). Note that the nodes vector is still necessary to
+* provide constant access to nodes based on indexes.
+*/
+private final HashMap<Object,Integer> nodeindex;
+
+/** Contains sets of node indexes. If "nodes" is not null, indices are 
+* defined by "nodes", otherwise they correspond to 0,1,... */
+private final ArrayList<Set<Integer>> neighbors;
+
+/** Indicates if the graph is directed. */
+private final boolean directed;
+
+// =================== public constructors ======================
+// ===============================================================
+
+/**
+* Constructs an empty graph. That is, the graph has zero nodes, but any
+* number of nodes and edges can be added later.
+* @param directed if true the graph will be directed
+*/
+public NeighbourListGraph( boolean directed ) {
+
+       nodes = new ArrayList<Object>(1000);    
+       neighbors = new ArrayList<Set<Integer>>(1000);
+       nodeindex = new HashMap<Object,Integer>(1000);
+       this.directed = directed;
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Constructs a graph with a fixed size without edges. If the graph is
+* constructed this way, it is not possible to associate objects to nodes,
+* nor it is possible to grow the graph using {@link #addNode}.
+* @param directed if true the graph will be directed
+*/
+public NeighbourListGraph( int size, boolean directed ) {
+
+       nodes = null;
+       neighbors = new ArrayList<Set<Integer>>(size);
+       for(int i=0; i<size; ++i) neighbors.add(new HashSet<Integer>());
+       nodeindex = null;
+       this.directed = directed;
+}
+
+// =================== public methods =============================
+// ================================================================
+
+/**
+* If the given object is not associated with a node yet, adds a new
+* node. Returns the index of the node. If the graph was constructed to have
+* a specific size, it is not possible to add nodes and therefore calling
+* this method will throw an exception.
+* @throws NullPointerException if the size was specified at construction time.
+*/
+public int addNode( Object o ) {
+
+       Integer index = nodeindex.get(o);
+       if( index == null )
+       {
+               index = nodes.size();
+               nodes.add(o);
+               neighbors.add(new HashSet<Integer>());
+               nodeindex.put(o,index);
+       }
+
+       return index;
+}
+
+
+// =================== graph implementations ======================
+// ================================================================
+
+
+public boolean setEdge( int i, int j ) {
+       
+       boolean ret = neighbors.get(i).add(j);
+       if( ret && !directed ) neighbors.get(j).add(i);
+       return ret;
+}
+
+// ---------------------------------------------------------------
+
+public boolean clearEdge( int i, int j ) {
+       
+       boolean ret = neighbors.get(i).remove(j);
+       if( ret && !directed ) neighbors.get(j).remove(i);
+       return ret;
+}
+
+// ---------------------------------------------------------------
+
+public boolean isEdge(int i, int j) {
+       
+       return neighbors.get(i).contains(j);
+}
+
+// ---------------------------------------------------------------
+
+public Collection<Integer> getNeighbours(int i) {
+       
+       return Collections.unmodifiableCollection(neighbors.get(i));
+}
+
+// ---------------------------------------------------------------
+
+/** If the graph was gradually grown using {@link #addNode}, returns the
+* object associated with the node, otherwise null */
+public Object getNode(int i) { return (nodes==null?null:nodes.get(i)); }
+       
+// ---------------------------------------------------------------
+
+/**
+* Returns null always. 
+*/
+public Object getEdge(int i, int j) { return null; }
+
+// ---------------------------------------------------------------
+
+public int size() { return neighbors.size(); }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return directed; }
+
+// --------------------------------------------------------------------
+
+public int degree(int i) { return neighbors.get(i).size(); }
+}
+
+
+
+
diff --git a/contrib/psg/src/peersim/graph/PrefixSubGraph.java b/contrib/psg/src/peersim/graph/PrefixSubGraph.java
new file mode 100644 (file)
index 0000000..5098316
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.graph;
+
+import java.util.*;
+
+/**
+* This class is an adaptor for representing special subgraphs of any graph.
+* It can represent the subgraphs spanned by the nodes 0,...,i where
+* i is less than or equal to n-1, the last node of the original graph.
+* The underlying graph is stored by reference. This means that if the
+* graph changes, then these changes will be reflected by this class as well.
+* Besides, the size of the prefix can be changed at will at any time
+* using {@link #setSize}.
+*/
+public class PrefixSubGraph implements Graph {
+
+
+// ====================== private fileds ========================
+// ==============================================================
+
+
+private final Graph g;
+
+/** The graph represents the subgraph defined by nodes 0,...,prefSize */
+private int prefSize;
+
+
+// ====================== public constructors ===================
+// ==============================================================
+
+
+/**
+* Constructs an initially max size subgraph of g. That is, the subgraph will
+* contain all nodes.
+*/
+public PrefixSubGraph( Graph g ) {
+
+       this.g = g;
+       prefSize = g.size();
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+       
+       if( i<0 || i>=prefSize ) throw new IndexOutOfBoundsException();
+       if( j<0 || j>=prefSize ) throw new IndexOutOfBoundsException();
+       return g.isEdge(i,j);
+}
+
+// ---------------------------------------------------------------
+
+public Collection<Integer> getNeighbours(int i) {
+       
+       if( i<0 || i>=prefSize ) throw new IndexOutOfBoundsException();
+       
+       List<Integer> result = new LinkedList<Integer>();
+       for(Integer j:g.getNeighbours(i))
+       {
+               if( j < prefSize ) result.add(j);
+       }
+
+       return Collections.unmodifiableCollection(result);
+}
+
+// ---------------------------------------------------------------
+
+public Object getNode(int i) {
+
+       if( i<0 || i>=prefSize ) throw new IndexOutOfBoundsException();
+       return g.getNode(i);
+}
+       
+// ---------------------------------------------------------------
+
+/**
+* Returns the edge in the original graph if both i and j are smaller than
+* size().
+*/
+public Object getEdge(int i, int j) {
+       
+       if( isEdge(i,j) ) return g.getEdge(i,j);
+       return null;
+}
+
+// --------------------------------------------------------------------
+
+public int size() { return prefSize; }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return g.directed(); }
+
+// --------------------------------------------------------------------
+
+/** not supported */
+public boolean setEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+/** not supported */
+public boolean clearEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+public int degree(int i) {
+
+       if( i<0 || i>=prefSize ) throw new IndexOutOfBoundsException();
+       return g.degree(i);
+}
+       
+
+// ================= public functions =================================
+// ====================================================================
+
+
+/**
+* Sets the size of the subgraph. If i is negative, it is changed to 0 and
+* if it is larger than the underlying graph size, it is changed to the
+* underlying graph size (set at construction time).
+* @return old size.
+*/
+public int setSize(int i) {
+       
+       int was = prefSize;
+       if( i < 0 ) i = 0;
+       if( i > g.size() ) i=g.size();
+       prefSize=i;
+       return was;
+}
+}
+
diff --git a/contrib/psg/src/peersim/graph/SubGraphEdges.java b/contrib/psg/src/peersim/graph/SubGraphEdges.java
new file mode 100644 (file)
index 0000000..bb4201f
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.graph;
+
+import java.util.*;
+
+/**
+* This class is an adaptor for representing subgraphs of any graph.
+* The subgraph is defined the following way.
+* The subgraph always contains all the nodes of the original underlying
+* graph. However, it is possible to remove edges by flagging nodes as
+* removed, in which case
+* the edges that have at least one end on those nodes are removed.
+* If the underlying graph changes after initialization, this class follows
+* the change.
+*/
+public class SubGraphEdges implements Graph {
+
+
+// ====================== private fields ========================
+// ==============================================================
+
+
+private final Graph g;
+
+private final BitSet nodes;
+
+
+// ====================== public constructors ===================
+// ==============================================================
+
+
+/**
+* Constructs an initially empty subgraph of g. That is, the subgraph will
+* contain no nodes.
+*/
+public SubGraphEdges( Graph g ) {
+
+       this.g = g;
+       nodes = new BitSet(g.size());
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+       
+       return nodes.get(i) && nodes.get(j) && g.isEdge(i,j);
+}
+
+// ---------------------------------------------------------------
+
+public Collection<Integer> getNeighbours(int i) {
+       
+       List<Integer> result = new LinkedList<Integer>();
+       if( nodes.get(i) )
+       {
+               for(Integer in:g.getNeighbours(i))
+               {
+                       if( nodes.get(in) ) result.add(in);
+               }
+       }
+
+       return Collections.unmodifiableCollection(result);
+}
+
+// ---------------------------------------------------------------
+
+public Object getNode(int i) { return g.getNode(i); }
+       
+// ---------------------------------------------------------------
+
+/**
+* If both i and j are within the node set of the subgraph and the original
+* graph has an (i,j) edge, returns that edge.
+*/
+public Object getEdge(int i, int j) {
+       
+       if( isEdge(i,j) ) return g.getEdge(i,j);
+       return null;
+}
+
+// --------------------------------------------------------------------
+
+public int size() { return g.size(); }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return g.directed(); }
+
+// --------------------------------------------------------------------
+
+/** not supported */
+public boolean setEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+/** not supported */
+public boolean clearEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+public int degree(int i) {
+
+       int degree=0;
+       if( nodes.get(i) )
+       {
+               for(Integer in:g.getNeighbours(i))
+               {
+                       if( nodes.get(in) ) degree++;
+               }
+       }
+       return degree;
+}
+
+
+// ================= public functions =================================
+// ====================================================================
+
+
+/**
+* This function returns the size of the subgraph, i.e. the number of nodes
+* in the subgraph.
+*/
+public int subGraphSize() { return nodes.cardinality(); }
+
+// --------------------------------------------------------------------
+
+/**
+* Removes given node from subgraph.
+* @return true if the node was already in the subgraph otherwise false.
+*/
+public boolean removeNode(int i) {
+       
+       boolean was = nodes.get(i);
+       nodes.clear(i);
+       return was;
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Adds given node to subgraph.
+* @return true if the node was already in the subgraph otherwise false.
+*/
+public boolean addNode(int i) {
+       
+       boolean was = nodes.get(i);
+       nodes.set(i);
+       return was;
+}
+}
+
diff --git a/contrib/psg/src/peersim/graph/UndirectedGraph.java b/contrib/psg/src/peersim/graph/UndirectedGraph.java
new file mode 100644 (file)
index 0000000..d229bae
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.graph;
+
+import java.util.*;
+
+/**
+* This class is an adaptor making any Graph an undirected graph
+* by making its edges bidirectional. The graph to be made undirected
+* is passed to the constructor. Only the reference is stored so
+* if the directed graph changes later, the undirected version will
+* follow that change. However, {@link #getNeighbours} has O(n) time complexity
+* (in other words, too slow for large graphs).
+* @see ConstUndirGraph
+*/
+public class UndirectedGraph implements Graph {
+
+
+// ====================== private fileds ========================
+// ==============================================================
+
+
+private final Graph g;
+
+
+// ====================== public constructors ===================
+// ==============================================================
+
+
+public UndirectedGraph( Graph g ) {
+
+       this.g = g;
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+       
+       return g.isEdge(i,j) || g.isEdge(j,i);
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Uses sets as collection so does not support multiple edges now, even if
+* the underlying directed graph does.
+*/
+public Collection<Integer> getNeighbours(int i) {
+       
+       Set<Integer> result = new HashSet<Integer>();
+       result.addAll(g.getNeighbours(i));
+       final int max = g.size();
+       for(int j=0; j<max; ++j)
+       {
+               if( g.isEdge(j,i) ) result.add(j);
+       }
+
+       return Collections.unmodifiableCollection(result);
+}
+
+// ---------------------------------------------------------------
+
+public Object getNode(int i) { return g.getNode(i); }
+       
+// ---------------------------------------------------------------
+
+/**
+* If there is an (i,j) edge, returns that, otherwise if there is a (j,i)
+* edge, returns that, otherwise returns null.
+*/
+public Object getEdge(int i, int j) {
+       
+       if( g.isEdge(i,j) ) return g.getEdge(i,j);
+       if( g.isEdge(j,i) ) return g.getEdge(j,i);
+       return null;
+}
+
+// ---------------------------------------------------------------
+
+public int size() { return g.size(); }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return false; }
+
+// --------------------------------------------------------------------
+
+/** not supported */
+public boolean setEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+/** not supported */
+public boolean clearEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// --------------------------------------------------------------------
+
+public int degree(int i) {
+       
+       return getNeighbours(i).size();
+}
+
+// --------------------------------------------------------------------
+/*
+public static void main( String[] args ) {
+
+       
+       Graph net = null;       
+       UndirectedGraph ug = new UndirectedGraph(net);
+       for(int i=0; i<net.size(); ++i)
+               System.err.println(i+" "+net.getNeighbours(i));
+       System.err.println("============");
+       for(int i=0; i<ug.size(); ++i)
+               System.err.println(i+" "+ug.getNeighbours(i));
+       for(int i=0; i<ug.size(); ++i)
+       {
+               for(int j=0; j<ug.size(); ++j)
+                       System.err.print(ug.isEdge(i,j)?"W ":"- ");
+               System.err.println();
+       }
+
+       GraphIO.writeGML(net,System.out);
+}
+*/
+}
+
+
diff --git a/contrib/psg/src/peersim/rangesim/ProcessHandler.java b/contrib/psg/src/peersim/rangesim/ProcessHandler.java
new file mode 100644 (file)
index 0000000..92537ec
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.rangesim;
+
+public interface ProcessHandler
+{
+
+/**
+ * Stop the external process managed by this object.
+ */
+public abstract void doStop();
+
+/**
+ * Wait until the process has terminated. 
+ * @exception InterruptedException 
+ *   thrown if the wait is interrupted
+ */
+public abstract void join()
+  throws InterruptedException;
+
+}
\ No newline at end of file
diff --git a/contrib/psg/src/peersim/rangesim/ProcessManager.java b/contrib/psg/src/peersim/rangesim/ProcessManager.java
new file mode 100644 (file)
index 0000000..1ccfc79
--- /dev/null
@@ -0,0 +1,53 @@
+package peersim.rangesim;
+
+import java.util.*;
+
+/**
+ * This thread is used to kill forked processes in the case of an abnormal
+ * termination of the Java virtual machine (for example, due to a signal).
+ */
+public class ProcessManager extends Thread
+{
+
+/** The threads that must be killed */
+private List<ProcessHandler> threads;
+
+public ProcessManager()
+{
+       threads = Collections.synchronizedList(new ArrayList<ProcessHandler>());
+}
+
+public void addThread(ProcessHandler p)
+{
+       threads.add(p);
+}
+
+/**
+ * Assumes that the process manager
+ */
+public void joinAll()
+{
+       int i=0;
+       while (i < threads.size()) {
+               try {
+                       threads.get(i).join();
+                       i++;
+               } catch (InterruptedException e) {
+               }
+       }
+}
+
+
+/**
+ * Kill the child process.
+ */
+public void run()
+{
+       System.err.println("Terminating simulation.");
+       for (int i=0; i < threads.size(); i++) {
+               if (threads.get(i) != null)
+                       threads.get(i).doStop();
+       }
+}
+
+}
\ No newline at end of file
diff --git a/contrib/psg/src/peersim/rangesim/RangeSimulator.java b/contrib/psg/src/peersim/rangesim/RangeSimulator.java
new file mode 100644 (file)
index 0000000..0995bcc
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.rangesim;
+
+import java.io.*;
+import java.util.*;
+
+import peersim.*;
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * This class is the main class for the Range Simulator. A range is
+ * a collection of values <em>S</em> to be assigned to a variable 
+ * <em>v</em>. The Range Simulator invokes the standard Peersim 
+ * simulator once for each distinct value. If multiple ranges 
+ * <em>S1, S2, ..., Sn</em> are specified, the standard Peersim
+ * simulator is invoked for each element in 
+ * <em>S1 * S2 * ... * Sn</em>.  
+ * <p>  
+ * Ranges are specified with the following syntax:
+<pre>
+range.[id] [var];[range]
+</pre>
+ * where:
+ * <UL>
+ * <LI> {@value #PAR_RANGE} is the prefix for all range
+ * specifications;</LI>
+ * <LI> <code>id</code> is an identifier; since they are not referred anywhere else,
+ * consecutive numbers are a good choice for range identifiers;</LI>
+ * <LI> <code>var</code> is a variable parameter </LI>
+ * <LI> <code>range</code> describes the collection of values to be associated
+ * to <code>var</code>, whose syntax and semantics is defined in 
+ * {@link peersim.util.StringListParser}. </LI>
+ * </UL>
+ * Examples of range specifications are the following:
+<pre>
+range.0 SIZE;2^10:2^18|*2
+range.1 K;20:30
+range.2 CHURN;0.05,0.10,0.20 
+</pre>
+ * With this specification, the collection of values associated to 
+ * <code>SIZE</code> is {2^10,2^11,...,2^18}; <code>K</code> contains 
+ * {20,21,22,...,30}, while <code>CHURN</code> contains just the
+ * specified values.
+ * <p>
+ * Values can be specified as constant expressions (like 2^10, (5+10), etc.)
+ * but variables cannot be used. 
+ * <p>
+ * A separate Java virtual machine is invoked to run each of the
+ * experiments. An attempt is done to run the same JVM version as
+ * the one running the Range Simulator; if this is not possible
+ * (for example due to path problems), the command shell mechanism
+ * is used to run the first JVM version found in the path.
+ * </p>
+ * It is possible to specify options for the forked JVM using the
+ * {@value #PAR_JVM} parameter on the command line. For example,
+ * a command line like this:
+<pre>
+java peersim.rangesim.RangeSimulator config.file jvm.options=-Xmx256m
+</pre>
+ * can be used to run the forked JVM with a maximum heap of 256MB.
+ * <p>
+ * The new JVM inherits the same classpath as the JVM running the
+ * RangeSimulator. The {@value #PAR_JVM} parameter can be used to
+ * specify additional classpath specification.
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.11 $
+ */
+public class RangeSimulator implements ProcessHandler
+{
+
+// --------------------------------------------------------------------------
+// Configuration parameters
+// --------------------------------------------------------------------------
+
+/**
+ * This is the prefix of the config properties whose value vary during
+ * a set of experiments.
+ * @config
+ */
+private static final String PAR_RANGE = "range";
+
+/**
+ * This config property can be used to set options in the JVMs that
+ * are forked to execute experiments with different configuration
+ * parameters.
+ * @config
+ */
+public static final String PAR_JVM = "jvm.options";
+
+
+// --------------------------------------------------------------------------
+// Static variables
+// --------------------------------------------------------------------------
+
+/** Names of range parameters */
+private String[] pars;
+
+/** Values to be simulated, for each parameter */
+private String[][] values;
+
+/** The jvm options to be used when creating jvms */
+private String[] jvmoptions;
+
+/** Command line arguments */
+private String[] args;
+
+/** The current process that is executed */
+private Process p;
+
+
+// --------------------------------------------------------------------------
+// Main
+// --------------------------------------------------------------------------
+
+/**
+ * Main method of the system.
+ */
+public static void main(String[] args)
+{
+       RangeSimulator r = new RangeSimulator(args);
+       r.run();
+}
+
+//--------------------------------------------------------------------------
+// Constructor
+//--------------------------------------------------------------------------
+
+public RangeSimulator(String[] args)
+{
+
+       // Check if there are no arguments or there is an explicit --help
+       // flag; if so, print the usage of the class
+       if (args.length == 0 || args[0].equals("--help")) {
+               usage();
+               System.exit(101);
+       }
+
+       this.args = args.clone();
+
+       // Read property file
+       System.err.println("Simulator: loading configuration");
+       Properties properties = new ParsedProperties(args);
+       Configuration.setConfig(properties);
+       
+       // Read jvm options and separate them in different strings
+       String opt = Configuration.getString(PAR_JVM, null);
+       if (opt == null)
+               jvmoptions = new String[0];
+       else
+               jvmoptions = opt.split(" ");
+
+       // Parse range parameters
+       parseRanges();
+
+}
+
+/**
+ * Main method to be executed
+ */
+public void run()
+{
+       // Shutdown thread management
+       ProcessManager t = new ProcessManager();
+       t.addThread(this);
+       Runtime.getRuntime().addShutdownHook(t);
+
+       // Executes experiments; report short messages about exceptions that are
+       // handled by the configuration mechanism.
+       try {
+               doExperiments(args);
+       } catch (MissingParameterException e) {
+               Runtime.getRuntime().removeShutdownHook(t);
+               System.err.println(e + "");
+               System.exit(101);
+       } catch (IllegalParameterException e) {
+               Runtime.getRuntime().removeShutdownHook(t);
+               System.err.println(e + "");
+               System.exit(101);
+       }
+       Runtime.getRuntime().removeShutdownHook(t);
+       System.exit(0);
+}
+
+// --------------------------------------------------------------------
+
+/**
+ * Parses a collection of range specifications and returns the set of
+ * parameter that will change during the simulation and the values that
+ * will be used for those parameters.
+ */
+private void parseRanges()
+{
+       // Get ranges
+       String[] ranges = Configuration.getNames(PAR_RANGE);
+
+       // Start is the first element in which ranges are stored
+       int start;
+       
+       // If there is an explicit simulation.experiment or there are no 
+       // ranges, put an experiment range at the beginning of the values.
+       // Otherwise, just use the ranges.
+       if (Configuration.contains(Simulator.PAR_EXPS) || ranges.length == 0) {
+               pars = new String[ranges.length + 1];
+               values = new String[ranges.length + 1][];
+               pars[0] = "EXP";
+               values[0] = StringListParser.parseList("1:"
+                               + Configuration.getInt(Simulator.PAR_EXPS, 1));
+               start = 1;
+       } else {
+               pars = new String[ranges.length];
+               values = new String[ranges.length][];
+               start = 0;
+       }
+
+       for (int i = start; i < pars.length; i++) {
+               String[] array = Configuration.getString(ranges[i-start]).split(";");
+               if (array.length != 2) {
+                       throw new IllegalParameterException(ranges[i],
+                                       " should be formatted as <parameter>;<value list>");
+               }
+               pars[i] = array[0];
+               values[i] = StringListParser.parseList(array[1]);
+       }
+}
+
+// --------------------------------------------------------------------
+
+/**
+ * Selects the next set of values by incrementing the specified index
+ * array. The index array is treated as a vector of digits; the first is
+ * managed managed as a vector of digits.
+ */
+private void nextValues(int[] idx, String[][] values)
+{
+       idx[idx.length - 1]++;
+       for (int j = idx.length - 1; j > 0; j--) {
+               if (idx[j] == values[j].length) {
+                       idx[j] = 0;
+                       idx[j - 1]++;
+               }
+       }
+}
+
+// --------------------------------------------------------------------
+
+private void doExperiments(String[] args)
+{
+
+       // Configure the java parameter for exception
+       String filesep = System.getProperty("file.separator");
+       String classpath = System.getProperty("java.class.path");
+       String javapath = System.getProperty("java.home") + filesep + "bin" + filesep
+                       + "java";
+       ArrayList<String> list = new ArrayList<String>(20);
+       list.add(javapath);
+       list.add("-cp");
+       list.add(classpath);
+       
+       // Add the jvm options
+       for (int i=0; i < jvmoptions.length; i++)
+               list.add(jvmoptions[i]);
+       
+       // The class to be run in the forked JVM
+       list.add("peersim.Simulator");
+       
+       // Parameters specified on the command line
+       for (int i=0; i < args.length; i++) {
+               list.add(args[i]);
+       }
+       
+       // Since multiple experiments are managed here, the value
+       // of standard variable for multiple experiments is changed to 1
+       list.add(Simulator.PAR_EXPS+"=1");
+
+       // Activate redirection to separate stdout from stderr
+       list.add(Simulator.PAR_REDIRECT+"="+TaggedOutputStream.class.getCanonicalName());
+       int startlog = list.size();
+       list.add(""); 
+       
+       // Create a placeholder for the seed
+       int startseed = list.size();
+       list.add("");
+       
+       // Create placeholders for the range parameters
+       int startpar = list.size();
+       for (int i=0; i < values.length; i++)
+               list.add("");
+               
+       // Execute with different values
+       int[] idx = new int[values.length]; // Initialized to 0
+       while (idx[0] < values[0].length) {
+
+               // Configure the argument string array
+               for (int j = 0; j < pars.length; j++) {
+                       list.set(startpar + j, pars[j] + "=" + values[j][idx[j]]);
+               }
+
+               // Fill the log placeholder
+               StringBuffer log = new StringBuffer();
+               for (int j = 0; j < pars.length; j++) {
+                       log.append(pars[j]);
+                       log.append(" ");
+                       log.append(values[j][idx[j]]);
+                       log.append(" ");
+               }
+               list.set(startlog, Simulator.PAR_REDIRECT+"."+
+                               TaggedOutputStream.PAR_RANGES+"="+log);
+
+               // Fill the seed place holder
+               long seed = CommonState.r.nextLong();
+               list.set(startseed, CommonState.PAR_SEED+"="+seed);
+
+               System.err.println("Experiment: " + log);
+               
+               executeProcess(list);
+
+               // Increment values
+               nextValues(idx, values);
+       
+       }
+}
+
+//--------------------------------------------------------------------
+
+/**
+ * Execute the "command line" represented by this String list.
+ * The first argument is the process to be executed. We try
+ * to run the same JVM as the current one. If not possible,
+ * we use the first java command found in the path.
+ */
+private void executeProcess(List<String> list)
+{
+       // Prepare the argument array for process forking
+       String[] newargs = new String[list.size()];
+
+       // Execute a new JVM
+       try {
+               ProcessBuilder pb = new ProcessBuilder(list.toArray(newargs));
+               pb.redirectErrorStream(true);
+               p = pb.start();
+       } catch (IOException e1) {
+               try {
+                       list.set(0, "java");
+                       ProcessBuilder pb = new ProcessBuilder(list.toArray(newargs));
+                       pb.redirectErrorStream(true);
+                       p = pb.start();
+               } catch (IOException e2) {
+                       System.err.println("Unable to launch a Java virtual machine");
+                       System.exit(1);
+               }
+       }
+
+       // Read the output from the process and redirect it to System.out
+       // and System.err.
+       BufferedReader toprint = new BufferedReader(new InputStreamReader(p
+                       .getInputStream()));
+       String line;
+       while ((line = getLine(toprint)) != null) {
+               if (line.length() == 0) {
+                       System.out.println();
+               } else {
+                       int last = line.charAt(line.length()-1);
+                       if (last != TaggedOutputStream.TAG) {
+                               System.err.println(line);
+                       } else {
+                               line = line.substring(0, line.length()-1);
+                               System.out.println(line);
+                       }
+               }
+       }
+
+       // We close all the files and we destroy the process. They are not 
+       // cleaned when the process is closed. See:
+       // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4784692
+       // http://www.thescripts.com/forum/thread18019.html
+       try {
+               p.getErrorStream().close();
+               p.getInputStream().close();
+               p.getOutputStream().close();
+               p.destroy();
+       } catch (IOException e) {
+               e.printStackTrace();
+       }
+
+       // The static variable p (used also by ShutdownThread) is back to
+       // null - no process must be killed on shutdown.
+       p = null;
+       
+       
+
+}
+
+//--------------------------------------------------------------------
+
+private static String getLine(BufferedReader toprint)
+{
+       try {
+               return toprint.readLine();
+       } catch (IOException e) {
+               // If we get here, this means that the forked process has
+               // been killed by the shutdown thread. We just exit without
+         // printing this exception.
+               System.exit(1);
+               return null; // Never reached, but needed.
+       }
+}
+
+
+// --------------------------------------------------------------------
+
+private static void usage()
+{
+       System.err.println("Usage:");
+       System.err.println("  peersim.RangeSimulator <configfile> [property]*");
+}
+
+//--------------------------------------------------------------------
+
+RangeSimulator()
+{
+}
+
+/**
+ * Stop the process executing the external java virtual machine.
+ */
+public void doStop()
+{
+       if (p != null)
+               p.destroy();
+}
+
+/**
+ * Wait until the java virtual machine has terminated; it won't be
+ * used in this class, but you never know.
+ */
+public void join() throws InterruptedException
+{
+       p.waitFor();
+}
+
+}
diff --git a/contrib/psg/src/peersim/rangesim/TaggedOutputStream.java b/contrib/psg/src/peersim/rangesim/TaggedOutputStream.java
new file mode 100644 (file)
index 0000000..6288553
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.rangesim;
+
+import java.io.*;
+import java.util.*;
+
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * This OutputStream uses an underlying stream to output
+ * data. Each line (terminated with `\n`) is augmented
+ * with a tag character. This is used to discriminate
+ * among standard error and standard output. This 
+ * feature is needed for launching new JVMs; it should
+ * not be used for other purposes. 
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.5 $
+ */
+public class TaggedOutputStream extends PrintStream
+{
+
+//--------------------------------------------------------------------------
+//Constants
+//--------------------------------------------------------------------------
+
+/** 
+ * This character is appended at the end of each line. 
+ */
+public static final int TAG = 1;
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * This parameter contains the string that should be printed on each 
+ * line, containing the values of the range parameters for the experiment
+ * which is being run. The full name of this configuration string is
+ * prefixed by {@value peersim.Simulator#PAR_REDIRECT}.
+ * @config
+ */
+public static final String PAR_RANGES = "ranges";
+
+/**
+ * This parameter contains the list of observers for which the string
+ * contained in parameter {@value #PAR_RANGES} should be augmented with 
+ * a "TIME &lt;t&gt;" specification regarding current time. Observers are 
+ * separated by one of this characters: ' ' - ',' - ';'.
+ * @config
+ */
+public static final String PAR_TIME = "simulation.timed-observers";
+
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/** Variable used to save the original System.out to simplify printing */
+private PrintStream stdout;
+
+/** Buffer used to store a single line; it can grow */
+private byte[] buffer = new byte[1024];
+
+/** Current size of the buffer */
+private int size;
+
+/** The value of the PAR_RANGES parameter */
+private final String ranges;
+
+/** The value of the PAR_TIME parameter */
+private final ArrayList<String> obstime;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+
+/**
+ * Creates a tagged output stream that prints the tagged
+ * output on the specified stream.
+ */
+public TaggedOutputStream(String prefix)
+{
+       super(System.out);
+       
+       obstime = new ArrayList<String>();
+       String[] obs = Configuration.getString(PAR_TIME, "").split("[ :,]");
+       for (int i=0; i < obs.length; i++) {
+               obstime.add("control." + obs[i]);
+       }
+       ranges = Configuration.getString(prefix + "." + PAR_RANGES, "");
+       stdout = System.out;
+       size = 0;
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+// Comment inherited from interface
+@Override
+public synchronized void write(byte[] b, int off, int len)
+{
+       if (size+len > buffer.length) {
+               byte[] tmp = new byte[Math.max(buffer.length*2, size+len)];
+               System.arraycopy(buffer, 0, tmp, 0, size);
+               buffer = tmp;
+       }
+       int last = off+len;
+       for (int i=off; i < last; i++) {
+               if (b[i] == '\n') {
+                       buffer[size++] = TAG;
+                       buffer[size++] = b[i];
+                       printLine();
+               }  else {
+                       buffer[size++] = b[i];
+               }
+       }
+}
+
+// Comment inherited from interface
+@Override
+public synchronized void write(int b)
+{
+       if (size == buffer.length) {
+               byte[] tmp = new byte[buffer.length*2];
+               System.arraycopy(buffer, 0, tmp, 0, size);
+               buffer = tmp;
+       }
+       if (b == '\n') {
+               buffer[size++] = TAG;
+               buffer[size++] = (byte) b;
+               printLine();
+       }  else {
+               buffer[size++] = (byte) b;
+       }
+}
+
+/** 
+ * Actually prints a line, inserting ranges and time
+ * when needed.
+ */
+private void printLine()
+{
+       String line = new String(buffer, 0, size);
+       String[] parts = line.split(":");
+       if (parts.length == 2) {
+               stdout.print(parts[0]);
+               stdout.print(": ");
+               stdout.print(ranges);
+               if (obstime.contains(parts[0]))
+                       stdout.print(" TIME " + CommonState.getTime() + " ");
+               stdout.print(parts[1]);
+       } else {
+               stdout.print(line);
+       }
+       size = 0;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/BallExpansion.java b/contrib/psg/src/peersim/reports/BallExpansion.java
new file mode 100644 (file)
index 0000000..b46e117
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.reports;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * Control to observe the ball expansion, that is,
+ * the number of nodes that are
+ * accessible from a given node in at most 1, 2, etc steps.
+ */
+public class BallExpansion extends GraphObserver
+{
+
+// ===================== fields =======================================
+// ====================================================================
+
+/**
+ * This parameter defines the maximal distance we care about.
+ * In other words, two nodes are further away, they will not be taken
+ * into account when calculating statistics.
+ * <p>
+ * Defaults to the
+ * network size (which means all distances are taken into account).
+ * Note that this default is normally way too much; many low diameter graphs
+ * have only short distances between the nodes. Setting a short
+ * (but sufficient) distance saves memory.
+ * Also note that the <em>initial</em> network
+ * size is used if no value is given which might not be what you want if e.g. the
+ * network is growing.
+ * @config
+ */
+private static final String PAR_MAXD = "maxd";
+
+/**
+ * The number of nodes to print info about.
+ * Defaults to 1000. If larger than the current network size, then the
+ * current network size is used.
+ * @config
+ */
+private static final String PAR_N = "n";
+
+/**
+ * If defined, statistics are printed instead over the minimal path lengths. Not
+ * defined by default.
+ * @config
+ */
+private static final String PAR_STATS = "stats";
+
+private final int maxd;
+
+private final int n;
+
+private final boolean stats;
+
+/** working variable */
+private final int[] b;
+
+private final RandPermutation rp = new RandPermutation(CommonState.r);
+
+// ===================== initialization ================================
+// =====================================================================
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public BallExpansion(String name)
+{
+       super(name);
+       maxd = Configuration.getInt(name + "." + PAR_MAXD, Network.size());
+       n = Configuration.getInt(name + "." + PAR_N, 1000);
+       stats = Configuration.contains(name + "." + PAR_STATS);
+       b = new int[maxd];
+}
+
+// ====================== methods ======================================
+// =====================================================================
+
+/**
+* Prints information about ball expansion. It uses {@value #PAR_N} nodes to
+* collect statistics.
+* If parameter {@value #PAR_STATS} is defined then the output is
+* produced by {@link IncrementalStats#toString}, over the values of minimal
+* distances from the given number of nodes to all other nodes in the network.
+* If at least one node is unreachable from any selected starting node, then
+* the path length is taken as infinity and statistics are calculated
+* accordingly. In that case, {@link IncrementalStats#getMaxCount()} returns
+* the number of nodes of "infinite distance", that is, the number of
+* unreachable nodes.
+* Otherwise one line is printed for all nodes we observe, containing the
+* number of nodes at distance 1, 2, etc, separated by spaces.
+* In this output format, unreachable nodes are simply ignored, but of course
+* the sum of the numbers in one line can be used to detect partitioning if
+* necessary.
+* Finally, note that the {@value #PAR_N} nodes are not guaranteed to be the
+* same nodes over consecutive calls to this method.
+* @return always false
+*/
+public boolean execute() {
+
+       updateGraph();
+       System.out.print(name + ": ");
+       rp.reset(g.size());
+       if (stats)
+       {
+               IncrementalStats is = new IncrementalStats();
+               for (int i = 0; i < n && i < g.size(); ++i)
+               {
+                       ga.dist(g, rp.next());
+                       for (int j=0; j<g.size(); j++)
+                       {
+                               if (ga.d[j] > 0)
+                                       is.add(ga.d[j]);
+                               else if (ga.d[j] == -1)
+                                       is.add(Double.POSITIVE_INFINITY);
+                               // deliberately left ga.d[j]==0 out, as we don't
+                               // want to count trivial distance to oneself.
+                       }
+               }
+               System.out.println(is);
+       }
+       else
+       {
+               System.out.println();
+               for (int i = 0; i < n && i < g.size(); ++i)
+               {
+                       ga.flooding(g, b, rp.next());
+                       int j = 0;
+                       while (j < b.length && b[j] > 0)
+                       {
+                               System.out.print(b[j++] + " ");
+                       }
+                       System.out.println();
+               }
+       }
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/Clustering.java b/contrib/psg/src/peersim/reports/Clustering.java
new file mode 100644 (file)
index 0000000..38b81f7
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.reports;
+
+import peersim.config.Configuration;
+import peersim.graph.GraphAlgorithms;
+import peersim.util.IncrementalStats;
+
+/**
+ * Control to observe the clustering coefficient.
+ * @see GraphAlgorithms#clustering
+ */
+public class Clustering extends GraphObserver
+{
+
+// ===================== fields =======================================
+// ====================================================================
+
+/**
+ * The number of nodes to collect info about. Defaults to the size of the graph.
+ * @config
+ */
+private static final String PAR_N = "n";
+
+private final int n;
+
+// ===================== initialization ================================
+// =====================================================================
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public Clustering(String name)
+{
+       super(name);
+       n = Configuration.getInt(name + "." + PAR_N, Integer.MAX_VALUE);
+}
+
+// ====================== methods ======================================
+// =====================================================================
+
+/**
+* Prints information about the clustering coefficient.
+* It uses {@value #PAR_N} nodes to collect statistics.
+* The output is
+* produced by {@link IncrementalStats#toString}, over the values of
+* the clustering coefficients of the given number of nodes.
+* Clustering coefficients are calculated by {@link GraphAlgorithms#clustering}.
+* @return always false
+*/
+public boolean execute()
+{
+       IncrementalStats stats = new IncrementalStats();
+       updateGraph();
+       for (int i = 0; i < n && i < g.size(); ++i) {
+               stats.add(GraphAlgorithms.clustering(g, i));
+       }
+       System.out.println(name + ": " + stats);
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/ConnectivityObserver.java b/contrib/psg/src/peersim/reports/ConnectivityObserver.java
new file mode 100644 (file)
index 0000000..d23ac08
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.reports;
+
+import java.util.Iterator;
+import java.util.Map;
+import peersim.config.Configuration;
+import peersim.util.IncrementalStats;
+
+/**
+ * Reports statistics about connectivity properties of the network, such as
+ * weakly or strongly connected clusters.
+ */
+public class ConnectivityObserver extends GraphObserver
+{
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The parameter used to request cluster size statistics instead of the usual
+ * list of clusters. Not set by default.
+ * @config
+ */
+private static final String PAR_STATS = "stats";
+
+/**
+ * Defines the types of connected clusters to discover.
+ * Possible values are
+ * <ul>
+ * <li>"wcc": weakly connected clusters</li>
+ * <li>"scc": strongly connected clusters</li>
+ * </ul>
+ * Defaults to "wcc".
+ * @config
+ */
+private static final String PAR_TYPE = "type";
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/** {@link #PAR_STATS} */
+private final boolean sizestats;
+
+/** {@link #PAR_TYPE} */
+private final String type;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public ConnectivityObserver(String name)
+{
+       super(name);
+       sizestats = Configuration.contains(name + "." + PAR_STATS);
+       type = Configuration.getString(name + "." + PAR_TYPE,"wcc");
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/**
+* Prints information about clusters.
+* If parameter {@value #PAR_STATS} is defined then the output is
+* produced by {@link IncrementalStats#toString}, over the sizes of the
+* clusters.
+* Otherwise one line is printed that contains the string representation of
+* a map, that holds cluster IDs mapped to cluster sizes.
+* The meaning of the cluster IDs is not specified, but is printed for
+* debugging purposes.
+* @return always false
+* @see peersim.graph.GraphAlgorithms#tarjan
+* @see peersim.graph.GraphAlgorithms#weaklyConnectedClusters
+*/
+public boolean execute()
+{
+       Map clst;
+       updateGraph();
+       
+       if(type.equals("wcc"))
+               clst=ga.weaklyConnectedClusters(g);
+       else if(type.equals("scc"))
+               clst=ga.tarjan(g);
+       else
+               throw new RuntimeException(
+               "Unsupported connted cluster type '"+type+"'");
+
+       if (!sizestats) {
+               System.out.println(name + ": " + clst);
+       } else {
+               IncrementalStats stats = new IncrementalStats();
+               Iterator it = clst.values().iterator();
+               while (it.hasNext()) {
+                       stats.add(((Integer) it.next()).intValue());
+               }
+               System.out.println(name + ": " + stats);
+       }
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/DegreeStats.java b/contrib/psg/src/peersim/reports/DegreeStats.java
new file mode 100644 (file)
index 0000000..d6c57e6
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.reports;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * Prints several statistics about the node degrees in the graph.
+ */
+public class DegreeStats extends GraphObserver
+{
+
+//--------------------------------------------------------------------------
+//Parameter
+//--------------------------------------------------------------------------
+
+/**
+ * The number of nodes to be used for sampling the degree. 
+ * Defaults to full size of the graph.
+ * @config
+ */
+private static final String PAR_N = "n";
+
+/**
+ * If defined, then the given number of nodes will be traced. That is, it is
+ * guaranteed that in each call the same nodes will be picked in the same order.
+ * If a node being traced fails, its degree will be considered 0. Not defined by
+ * default.
+ * @config
+ */
+private static final String PAR_TRACE = "trace";
+
+/**
+ * Selects a method to use when printing results. Three methods are known:
+ * "stats" will use {@link IncrementalStats#toString}. "freq" will
+ * use {@link IncrementalFreq#print}. "list" will print the
+ * degrees of the sample nodes one by one in one line, separated by spaces.
+ * Default is "stats".
+ * @config
+ */
+private static final String PAR_METHOD = "method";
+
+/**
+ * Selects the types of links to print information about. Three methods are
+ * known: "live": links pointing to live nodes, "dead": links pointing to nodes
+ * that are unavailable and "all": both dead and live links summed. "all" and
+ * "dead" require parameter {@value peersim.reports.GraphObserver#PAR_UNDIR} 
+ * to be unset (graph must be directed). Default is "live".
+ * @config
+ */
+private static final String PAR_TYPE = "linktype";
+
+//--------------------------------------------------------------------------
+//Parameter
+//--------------------------------------------------------------------------
+
+private final int n;
+
+private final boolean trace;
+
+private Node[] traced = null;
+
+private final String method;
+
+private final String type;
+
+private final RandPermutation rp = new RandPermutation(CommonState.r);
+
+private int nextnode = 0;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public DegreeStats(String name)
+{
+       super(name);
+       n = Configuration.getInt(name + "." + PAR_N, -1);
+       trace = Configuration.contains(name + "." + PAR_TRACE);
+       method = Configuration.getString(name + "." + PAR_METHOD, "stats");
+       type = Configuration.getString(name + "." + PAR_TYPE, "live");
+       if ((type.equals("all") || type.equals("dead")) && undir) {
+               throw new IllegalParameterException(
+                       name + "." + PAR_TYPE, " Parameter "+ name + "." +
+                       PAR_UNDIR + " must not be defined if " + name + "."
+                       + PAR_TYPE + "=" + type + ".");
+       }
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Returns next node to get degree information about.
+ */
+private int nextNodeId()
+{
+       if (trace) {
+               if (traced == null) {
+                       int nn = (n < 0 ? Network.size() : n);
+                       traced = new Node[nn];
+                       for (int j = 0; j < nn; ++j)
+                               traced[j] = Network.get(j);
+               }
+               return traced[nextnode++].getIndex();
+       } else
+               return rp.next();
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * Returns degree information about next node.
+ */
+private int nextDegree()
+{
+       final int nodeid = nextNodeId();
+       if (type.equals("live")) {
+               return g.degree(nodeid);
+       } else if (type.equals("all")) {
+               return ((OverlayGraph) g).fullDegree(nodeid);
+       } else if (type.equals("dead")) {
+               return ((OverlayGraph) g).fullDegree(nodeid) - g.degree(nodeid);
+       } else
+               throw new RuntimeException(name + ": invalid type");
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * Prints statistics about node degree. The format of the output is specified
+ * by {@value #PAR_METHOD}. See also the rest of the configuration parameters.
+ * @return always false
+ */
+public boolean execute()
+{
+       updateGraph();
+       if (!trace)
+               rp.reset(g.size());
+       else
+               nextnode = 0;
+       final int nn = (n < 0 ? Network.size() : n);
+       if (method.equals("stats")) {
+               IncrementalStats stats = new IncrementalStats();
+               for (int i = 0; i < nn; ++i)
+                       stats.add(nextDegree());
+               System.out.println(name + ": " + stats);
+       } else if (method.equals("freq")) {
+               IncrementalFreq stats = new IncrementalFreq();
+               for (int i = 0; i < nn; ++i)
+                       stats.add(nextDegree());
+               stats.print(System.out);
+               System.out.println("\n\n");
+       } else if (method.equals("list")) {
+               System.out.print(name + ": ");
+               for (int i = 0; i < nn; ++i)
+                       System.out.print(nextDegree() + " ");
+               System.out.println();
+       }
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/GraphObserver.java b/contrib/psg/src/peersim/reports/GraphObserver.java
new file mode 100644 (file)
index 0000000..6f939ea
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.reports;
+
+import peersim.core.*;
+import peersim.config.Configuration;
+import peersim.graph.*;
+import peersim.cdsim.CDState;
+
+/**
+* Class that provides functionality for observing graphs.
+* It can efficiently create an undirected version of the graph, making sure
+* it is updated only when the simulation has advanced already, and provides
+* some common parameters.
+*/
+public abstract class GraphObserver implements Control {
+
+
+// ===================== fields =======================================
+// ====================================================================
+
+/**
+ * The protocol to operate on.
+ * @config
+ */
+private static final String PAR_PROT = "protocol";
+
+/**
+ * If defined, the undirected version of the graph will be analyzed. Not defined
+ * by default.
+ * @config
+ */
+protected static final String PAR_UNDIR = "undir";
+
+/**
+* Alias for {@value #PAR_UNDIR}.
+* @config
+*/
+private static final String PAR_UNDIR_ALT = "undirected";
+
+/**
+ * If defined, the undirected version of the graph will be stored using much
+ * more memory but observers will be in general a few times faster. As a
+ * consequence, it will not work with large graphs. Not defined by default. It
+ * is a static property, that is, it affects all graph observers that are used
+ * in a simulation. That is, it is not a parameter of any observer, the name
+ * should be specified as a standalone property.
+ * @config
+ */
+private static final String PAR_FAST = "graphobserver.fast";
+
+/** The name of this observer in the configuration */
+protected final String name;
+
+protected final int pid;
+
+protected final boolean undir;
+
+protected final GraphAlgorithms ga = new GraphAlgorithms();
+
+protected Graph g;
+
+// ---------------------------------------------------------------------
+
+private static int lastpid = -1234;
+
+private static long time = -1234;
+
+private static int phase = -1234;
+
+private static int ctime = -1234;
+
+private static Graph dirg;
+
+private static Graph undirg;
+
+private static boolean fast;
+
+/** If any instance of some extending class defines undir we need to
+maintain an undir graph. Note that the graph is stored in a static
+field so it is common to all instances. */
+private static boolean needUndir=false;
+
+// ===================== initialization ================================
+// =====================================================================
+
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+protected GraphObserver(String name) {
+
+       this.name = name;
+       pid = Configuration.getPid(name+"."+PAR_PROT);
+       undir = (Configuration.contains(name + "." + PAR_UNDIR) |
+               Configuration.contains(name + "." + PAR_UNDIR_ALT));
+       GraphObserver.fast = Configuration.contains(PAR_FAST);
+       GraphObserver.needUndir = (GraphObserver.needUndir || undir);
+}
+
+
+// ====================== methods ======================================
+// =====================================================================
+
+/**
+* Sets {@link #g}.
+* It MUST be called by any implementation of {@link #execute()} before
+* doing anything else.
+* Attempts to initialize {@link #g} from a
+* pre-calculated graph stored in a static field, but first it
+* checks whether it needs to be updated.
+* If the simulation time has progressed or it was calculated for a different
+* protocol, then updates this static graph as well.
+* The purpose of this mechanism is to save the time of constructing the
+* graph if many observers are run on the same graph. Time savings can be very
+* significant if the undirected version of the same graph is observed by many
+* observers.
+*/
+protected void updateGraph() {
+       
+       if( CommonState.getTime() != GraphObserver.time ||
+           (CDState.isCD() && (CDState.getCycleT() != GraphObserver.ctime)) ||
+           CommonState.getPhase() != GraphObserver.phase ||
+           pid != GraphObserver.lastpid )
+       {
+               // we need to update the graphs
+               
+               GraphObserver.lastpid = pid;
+               GraphObserver.time = CommonState.getTime();
+               if( CDState.isCD() ) GraphObserver.ctime = CDState.getCycleT();
+               GraphObserver.phase = CommonState.getPhase();
+
+               GraphObserver.dirg = new OverlayGraph(pid);
+               if( GraphObserver.needUndir )
+               {
+                       if( fast )
+                               GraphObserver.undirg =
+                               new FastUndirGraph(GraphObserver.dirg);
+                       else
+                               GraphObserver.undirg =
+                               new ConstUndirGraph(GraphObserver.dirg);
+               }
+       }
+       
+       if( undir ) g = GraphObserver.undirg;
+       else g = GraphObserver.dirg;
+}
+
+}
+
+
+
diff --git a/contrib/psg/src/peersim/reports/GraphPrinter.java b/contrib/psg/src/peersim/reports/GraphPrinter.java
new file mode 100644 (file)
index 0000000..3317c10
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.reports;
+
+import peersim.config.Configuration;
+import peersim.graph.GraphIO;
+import peersim.util.FileNameGenerator;
+import java.io.PrintStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+* Prints the whole graph in a given format.
+*/
+public class GraphPrinter extends GraphObserver {
+
+
+// ===================== fields =======================================
+// ====================================================================
+
+/**
+* This is the prefix of the filename where the graph is saved.
+* The extension is ".graph" and after the prefix the basename contains
+* a numeric index that is incremented at each saving point.
+* If not given, the graph is dumped on the standard output.
+* @config
+*/
+private static final String PAR_BASENAME = "outf";
+
+/**
+* The name for the format of the output. Defaults to "neighborlist",
+* which is a plain dump of neighbors. The class
+* {@link peersim.dynamics.WireFromFile} can read this format.
+* Other supported formats are "chaco" to be used with Yehuda Koren's
+* Embedder, "netmeter" to be used with Sergi Valverde's netmeter and also
+* with pajek,
+* "edgelist" that dumps one (directed) node pair in each line for each edge,
+* "gml" that is a generic format of many graph tools, and "dot" that can
+* be used with the graphviz package.
+* @see GraphIO#writeEdgeList
+* @see GraphIO#writeChaco
+* @see GraphIO#writeNeighborList
+* @see GraphIO#writeNetmeter
+* @config
+*/
+private static final String PAR_FORMAT = "format";
+
+private final String baseName;
+
+private final FileNameGenerator fng;
+
+private final String format;
+
+
+// ===================== initialization ================================
+// =====================================================================
+
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public GraphPrinter(String name) {
+
+       super(name);
+       baseName = Configuration.getString(name+"."+PAR_BASENAME,null);
+       format = Configuration.getString(name+"."+PAR_FORMAT,"neighborlist");
+       if(baseName!=null) fng = new FileNameGenerator(baseName,".graph");
+       else fng = null;
+}
+
+
+// ====================== methods ======================================
+// =====================================================================
+
+
+/**
+* Saves the graph according to the specifications in the configuration.
+* @return always false
+*/
+public boolean execute() {
+try {  
+       updateGraph();
+       
+       System.out.print(name+": ");
+       
+       // initialize output streams
+       FileOutputStream fos = null;
+       PrintStream pstr = System.out;
+       if( baseName != null )
+       {
+               String fname = fng.nextCounterName();
+               fos = new FileOutputStream(fname);
+               System.out.println("writing to file "+fname);
+               pstr = new PrintStream(fos);
+       }
+       else    System.out.println();
+       
+       if( format.equals("neighborlist") )
+               GraphIO.writeNeighborList(g, pstr);
+       else if( format.equals("edgelist") )
+               GraphIO.writeEdgeList(g, pstr);
+       else if( format.equals("chaco") )
+               GraphIO.writeChaco(g, pstr);
+       else if( format.equals("netmeter") )
+               GraphIO.writeNetmeter(g, pstr);
+       else if( format.equals("gml") )
+               GraphIO.writeGML(g, pstr);
+       else if( format.equals("dot") )
+               GraphIO.writeDOT(g, pstr);
+       else
+               System.err.println(name+": unsupported format "+format);
+       
+       if( fos != null ) fos.close();
+       
+       return false;
+}
+catch( IOException e )
+{
+       throw new RuntimeException(e);
+}
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/reports/GraphStats.java b/contrib/psg/src/peersim/reports/GraphStats.java
new file mode 100644 (file)
index 0000000..a57773c
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.reports;
+
+import peersim.config.Configuration;
+import peersim.graph.GraphAlgorithms;
+import peersim.util.IncrementalStats;
+
+/**
+* Prints reports on the graph like average clustering and average path length,
+* based on random sampling of the nodes.
+* In fact its functionality is a subset of the union of {@link Clustering}
+* and {@link BallExpansion}, and therefore is redundant,
+* but it is there for historical reasons.
+* @see BallExpansion
+* @see Clustering
+*/
+public class GraphStats extends GraphObserver {
+
+
+// ===================== fields =======================================
+// ====================================================================
+
+/** 
+* The number of nodes to use for
+* sampling average path length.
+* Statistics are printed over a set of node pairs.
+* To create the set of pairs, we select the given number of different nodes
+* first, and then pair all these nodes with every other node in the network.
+* If zero is given, then no statistics
+* will be printed about path length. If a negative value is given then
+* the value is the full size of the graph.
+* Defaults to zero.
+* @config
+*/
+private static final String PAR_NL = "nl";
+
+/** 
+* The number of nodes to use to sample
+* average clustering.
+* If zero is given, then no statistics
+* will be printed about clustering. If a negative value is given then
+* the value is the full size of the graph.
+* Defaults to zero.
+* @config
+*/
+private static final String PAR_NC = "nc";
+
+private final int nc;
+
+private final int nl;
+
+
+// ===================== initialization ================================
+// =====================================================================
+
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public GraphStats(String name) {
+
+       super(name);
+       nl = Configuration.getInt(name+"."+PAR_NL,0);
+       nc = Configuration.getInt(name+"."+PAR_NC,0);
+}
+
+
+// ====================== methods ======================================
+// =====================================================================
+
+/**
+* Returns statistics over minimal path length and clustering.
+* The output is the average over the set of
+* clustering coefficients of randomly selected nodes, and the
+* set of distances from randomly selected nodes to all the other nodes.
+* The output is always concatenated in one line, containing zero, one or two
+* numbers (averages) as defined by the config parameters.
+* Note that the path length between a pair of nodes can be infinite, in which
+* case the statistics will reflect this (the average will be infinite, etc).
+* See also the configuration parameters.
+* @return always false
+* @see BallExpansion
+* @see Clustering
+*/
+public boolean execute() {
+       
+       System.out.print(name+": ");
+       
+       IncrementalStats stats = new IncrementalStats();
+       updateGraph();
+       
+       if( nc != 0 )
+       {
+               stats.reset();
+               final int n = ( nc<0 ? g.size() : nc );
+               for(int i=0; i<n && i<g.size(); ++i)
+               {
+                       stats.add(GraphAlgorithms.clustering(g,i));
+               }
+               System.out.print(stats.getAverage()+" ");
+       }
+       
+       if( nl != 0 )
+       {
+               stats.reset();
+               final int n = ( nl<0 ? g.size() : nl );
+               outerloop:
+               for(int i=0; i<n && i<g.size(); ++i)
+               {
+                       ga.dist(g,i);
+                       for(int j=0; j<g.size(); ++j)
+                       {
+                               if( j==i ) continue;
+                               if (ga.d[j] == -1)
+                               {
+                                       stats.add(Double.POSITIVE_INFINITY);
+                                       break outerloop;
+                               }
+                               else
+                                       stats.add(ga.d[j]); 
+                       }
+               }
+               System.out.print(stats.getAverage());
+       }
+       
+       System.out.println();
+       return false;
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/reports/MemoryObserver.java b/contrib/psg/src/peersim/reports/MemoryObserver.java
new file mode 100644 (file)
index 0000000..839108c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.reports;
+
+import peersim.core.*;
+
+/**
+ * This observer reports memory utilization (max, total and 
+ * free, as defined by <code>java.lang.Runtime</code>).
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.1 $
+ */
+public class MemoryObserver implements Control
+{
+
+/** The runtime object to obtain memory info */
+private final static Runtime r = Runtime.getRuntime(); 
+
+/** The prefix to be printed */
+private final String prefix;
+
+/**
+ * Constructor to be instantiated in PeerSim.
+ * @param prefix
+ */
+public MemoryObserver(String prefix)
+{
+       this.prefix = prefix;
+}
+
+public boolean execute()
+{
+       System.out.println(prefix + ": max=" + r.maxMemory() + ", total=" + 
+                       r.totalMemory() + ", free=" + r.freeMemory()); 
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/RandRemoval.java b/contrib/psg/src/peersim/reports/RandRemoval.java
new file mode 100644 (file)
index 0000000..8872873
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.reports;
+
+import peersim.core.*;
+import peersim.config.Configuration;
+import peersim.graph.*;
+import peersim.util.IncrementalStats;
+import java.util.Map;
+import java.util.Iterator;
+
+/**
+ * It tests the network for robustness to random node removal.
+ * It does not actually remove
+ * nodes, it is only an observer, so can be applied several times during the
+ * simulation. A warning though: as a side effect it <em>may
+ * shuffle the network</em> (see {@value #PAR_N}) so if this is an issue,
+ * it should not be used,
+ * or only after the simulation has finished.
+ */
+public class RandRemoval extends GraphObserver
+{
+
+// ===================== fields =======================================
+// ====================================================================
+
+// XXX remove side effect
+/**
+ * This parameter defines the number of runs of the iterative removal procedure
+ * to get statistics. Look out: if set to a value larger than 1 then as a side
+ * effect <em>the overlay will be shuffled</em>. Defaults to 1.
+ * @config
+ */
+private static final String PAR_N = "n";
+
+private final int n;
+
+// ===================== initialization ================================
+// =====================================================================
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public RandRemoval(String name)
+{
+       super(name);
+       n = Configuration.getInt(name + "." + PAR_N, 1);
+}
+
+// ====================== methods ======================================
+// =====================================================================
+
+/**
+* Prints results of node removal tests. The following experiment is
+* repeated {@value #PAR_N} times. From the graph 50%, 51%, ..., 99% of the nodes
+* are removed at random. For all percentages it is calculated what is
+* the maximal
+* clustersize (weakly connected clusters) and the number of
+* clusters in the remaining graph.
+* These values are averaged over the experiments, and for all 50 different
+* percentage values a line is printed that contains the respective averages,
+* first the average maximal cluster size, followed by the average number
+* of clusters.
+* @return always false
+*/
+public boolean execute()
+{
+       if( n < 1 ) return false;
+       updateGraph();
+       
+       System.out.println(name + ":");
+       
+       final int size = Network.size();
+       final int steps = 50;
+       IncrementalStats[] maxClust = new IncrementalStats[steps];
+       IncrementalStats[] clustNum = new IncrementalStats[steps];
+       for (int i = 0; i < steps; ++i) {
+               maxClust[i] = new IncrementalStats();
+               clustNum[i] = new IncrementalStats();
+       }
+       for (int j = 0; j < n; ++j) {
+               PrefixSubGraph sg = new PrefixSubGraph(g);
+               IncrementalStats stats = new IncrementalStats();
+               for (int i = 0; i < steps; i++) {
+                       sg.setSize(size / 2 - i * (size / 100));
+                       Map clst = ga.weaklyConnectedClusters(sg);
+                       stats.reset();
+                       Iterator it = clst.values().iterator();
+                       while (it.hasNext()) {
+                               stats.add(((Integer) it.next()).intValue());
+                       }
+                       maxClust[i].add(stats.getMax());
+                       clustNum[i].add(clst.size());
+               }
+               if( j+1 < n ) Network.shuffle();
+       }
+       for (int i = 0; i < steps; ++i) {
+               System.out.println(maxClust[i].getAverage() + " "
+                               + clustNum[i].getAverage());
+       }
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/transport/E2ENetwork.java b/contrib/psg/src/peersim/transport/E2ENetwork.java
new file mode 100644 (file)
index 0000000..a184f9a
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.transport;
+
+
+/**
+ * This static singleton emulates an underlying router network
+ * of fixed size, and stores the latency measurements for all pairs
+ * of routers.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.6 $
+ */
+public class E2ENetwork
+{
+
+//---------------------------------------------------------------------
+//Fields
+//---------------------------------------------------------------------
+
+/**
+ * True if latency between nodes is considered symmetric. False otherwise.
+ */
+private static boolean symm;   
+       
+/**
+ * Size of the router network. 
+ */
+private static int size;
+
+/**
+ * Latency distances between nodes.
+ */
+private static int[][] array;
+       
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/** Disable instance construction */
+private E2ENetwork() {}
+
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/**
+ * Resets the network, by creating a triangular (if symm is true) or
+ * a rectangular (if symm is false) array of integers. Initially all
+ * latencies between any pairs are set to be 0.
+ * @param size the number or routers
+ * @param symm if latency is symmetric between all pairs of routers
+ */
+public static void reset(int size, boolean symm)
+{
+       E2ENetwork.symm = symm;
+       E2ENetwork.size = size;
+       array = new int[size][];
+       for (int i=0; i < size; i++) {
+               if (symm)
+                       array[i] = new int[i];
+               else
+                       array[i] = new int[size];
+       }
+}
+       
+//---------------------------------------------------------------------
+
+/**
+ * Returns the latency associated to the specified (sender, receiver)
+ * pair. Routers are indexed from 0.
+ * 
+ * @param sender the index of the sender
+ * @param receiver the index of the receiver
+ * @return the latency associated to the specified (sender, receiver)
+ * pair.
+ */
+public static int getLatency(int sender, int receiver) 
+{
+       if (sender == receiver)
+               return 0;
+       // XXX There should be the possibility to fix the delay.
+       if (symm) {
+               // Symmetric network
+               if (sender < receiver) {
+                       int tmp = sender;
+                       sender = receiver;
+                       receiver = tmp;
+               }
+       } 
+       return array[sender][receiver];
+}
+
+//---------------------------------------------------------------------
+
+/**
+ * Sets the latency associated to the specified (sender, receiver)
+ * pair. Routers are indexed from 0.
+ * 
+ * @param sender the index of the sender
+ * @param receiver the index of the receiver
+ * @param latency the latency to be set
+ */
+public static void setLatency(int sender, int receiver, int latency) 
+{
+       if (symm) {
+               // Symmetric network
+               if (sender < receiver) {
+                       int tmp = sender;
+                       sender = receiver;
+                       receiver = tmp;
+               }
+       } 
+       array[sender][receiver] = latency;
+}
+
+//---------------------------------------------------------------------
+
+/**
+ * Returns the current size of the underlying network (i.e., the number of
+ * routers).
+ */
+public static int getSize()
+{
+       return size;
+}
+
+}
diff --git a/contrib/psg/src/peersim/transport/E2ETransport.java b/contrib/psg/src/peersim/transport/E2ETransport.java
new file mode 100644 (file)
index 0000000..e2eab78
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.transport;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.edsim.*;
+
+
+/**
+ * This transport protocol is based on the {@link E2ENetwork} class.
+ * Each instance
+ * of this transport class is assigned to one of the routers contained in
+ * the (fully static singleton) {@link E2ENetwork},
+ * and subsequently the {@link E2ENetwork} class is used to obtain the
+ * latency for messages sending based on the router assignment.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.11 $
+ */
+public class E2ETransport implements Transport, RouterInfo
+{
+
+//---------------------------------------------------------------------
+//Parameters
+//---------------------------------------------------------------------
+
+/**
+ * The delay that corresponds to the time spent on the source (and destination)
+ * nodes. In other words, full latency is calculated by fetching the latency
+ * that belongs to communicating between two routers, incremented by
+ * twice this delay. Defaults to 0.
+ * @config
+ */
+private static final String PAR_LOCAL = "local";
+       
+//---------------------------------------------------------------------
+//Static fields
+//---------------------------------------------------------------------
+
+/** Identifier of this transport protocol */
+private static int tid;
+       
+/** Local component of latency */
+private static long local;
+
+//---------------------------------------------------------------------
+//Fields
+//---------------------------------------------------------------------
+
+/** Identifier of the internal node */
+private int router = -1;
+       
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/**
+ * Reads configuration parameters.
+ */
+public E2ETransport(String prefix)
+{
+       tid = CommonState.getPid();
+       local = Configuration.getLong(prefix + "." + PAR_LOCAL, 0);
+}
+
+//---------------------------------------------------------------------
+
+/**
+ * Clones the object.
+ */
+public Object clone()
+{
+       E2ETransport e2e=null;
+       try { e2e=(E2ETransport)super.clone(); }
+       catch( CloneNotSupportedException e ) {} // never happens
+       return e2e;
+}
+
+//---------------------------------------------------------------------
+//Methods inherited by Transport
+//---------------------------------------------------------------------
+
+/**
+* Delivers the message reliably, with the latency calculated by
+* {@link #getLatency}.
+*/
+public void send(Node src, Node dest, Object msg, int pid)
+{
+       /* Assuming that the sender corresponds to the source node */
+       E2ETransport sender = (E2ETransport) src.getProtocol(tid);
+       E2ETransport receiver = (E2ETransport) dest.getProtocol(tid);
+       long latency =
+          E2ENetwork.getLatency(sender.router, receiver.router) + local*2;
+       EDSimulator.add(latency, msg, dest, pid);
+}
+
+//---------------------------------------------------------------------
+
+/**
+* Calculates latency using the static singleton {@link E2ENetwork}.
+* It looks up which routers the given nodes are assigned to, then
+* looks up the corresponding latency. Finally it increments this value
+* by adding twice the local delay configured by {@value #PAR_LOCAL}.
+*/
+public long getLatency(Node src, Node dest)
+{
+       /* Assuming that the sender corresponds to the source node */
+       E2ETransport sender = (E2ETransport) src.getProtocol(tid);
+       E2ETransport receiver = (E2ETransport) dest.getProtocol(tid);
+       return E2ENetwork.getLatency(sender.router, receiver.router) + local*2;
+}
+
+
+//---------------------------------------------------------------------
+//Methods inherited by RouterInfo
+//---------------------------------------------------------------------
+
+/**
+ * Associates the node hosting this transport protocol instance with
+ * a router in the router network.
+ * 
+ * @param router the numeric index of the router 
+ */
+public void setRouter(int router)
+{
+       this.router = router;
+}
+
+//---------------------------------------------------------------------
+
+/**
+ * @return the router associated to this transport protocol.
+ */
+public int getRouter()
+{
+       return router;
+}
+
+}
diff --git a/contrib/psg/src/peersim/transport/KingParser.java b/contrib/psg/src/peersim/transport/KingParser.java
new file mode 100644 (file)
index 0000000..1471796
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.transport;
+
+import java.io.*;
+import java.util.*;
+import peersim.config.*;
+import peersim.core.Control;
+
+/**
+ * Initializes static singleton {@link E2ENetwork} by reading a king data set.
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.9 $
+ */
+public class KingParser implements Control
+{
+
+// ---------------------------------------------------------------------
+// Parameters
+// ---------------------------------------------------------------------
+
+/**
+ * The file containing the King measurements.
+ * @config
+ */
+private static final String PAR_FILE = "file";
+
+/**
+ * The ratio between the time units used in the configuration file and the
+ * time units used in the Peersim simulator.
+ * @config
+ */
+private static final String PAR_RATIO = "ratio";
+
+// ---------------------------------------------------------------------
+// Fields
+// ---------------------------------------------------------------------
+
+/** Name of the file containing the King measurements. */
+private String filename;
+
+/**
+ * Ratio between the time units used in the configuration file and the time
+ * units used in the Peersim simulator.
+ */
+private double ratio;
+
+/** Prefix for reading parameters */
+private String prefix;
+
+// ---------------------------------------------------------------------
+// Initialization
+// ---------------------------------------------------------------------
+
+/**
+ * Read the configuration parameters.
+ */
+public KingParser(String prefix)
+{
+       this.prefix = prefix;
+       ratio = Configuration.getDouble(prefix + "." + PAR_RATIO, 1);
+       filename = Configuration.getString(prefix + "." + PAR_FILE, null);
+}
+
+// ---------------------------------------------------------------------
+// Methods
+// ---------------------------------------------------------------------
+
+/**
+ * Initializes static singleton {@link E2ENetwork} by reading a king data set.
+* @return  always false
+*/
+public boolean execute()
+{
+       BufferedReader in = null;
+       if (filename != null) {
+               try {
+                       in = new BufferedReader(new FileReader(filename));
+               } catch (FileNotFoundException e) {
+                       throw new IllegalParameterException(prefix + "." + PAR_FILE, filename
+                                       + " does not exist");
+               }
+       } else {
+               in = new BufferedReader( new InputStreamReader(
+                                               ClassLoader.getSystemResourceAsStream("t-king.map")
+                                       )       );
+       }
+               
+       // XXX If the file format is not correct, we will get quite obscure
+       // exceptions. To be improved.
+
+       String line = null;
+       // Skip initial lines
+       int size = 0;
+       int lc = 1;
+       try {
+               while ((line = in.readLine()) != null && !line.startsWith("node")) lc++;
+               while (line != null && line.startsWith("node")) {
+                       size++;
+                       lc++;
+                       line = in.readLine();
+               }
+       } catch (IOException e) {
+               System.err.println("KingParser: " + filename + ", line " + lc + ":");
+               e.printStackTrace();
+               try { in.close(); } catch (IOException e1) { };
+               System.exit(1);
+       }
+       E2ENetwork.reset(size, true);
+       if (line == null) {
+               System.err.println("KingParser: " + filename + ", line " + lc + ":");
+               System.err.println("No latency matrix contained in the specified file");
+               try { in.close(); } catch (IOException e1) { };
+               System.exit(1);
+       }
+       
+       System.err.println("KingParser: read " + size + " entries");
+       
+       try {
+               do {
+                       StringTokenizer tok = new StringTokenizer(line, ", ");
+                       if (tok.countTokens() != 3) {
+                               System.err.println("KingParser: " + filename + ", line " + lc + ":");
+                               System.err.println("Specified line does not contain a <node1, node2, latency> triple");
+                               try { in.close(); } catch (IOException e1) { };
+                               System.exit(1);
+                       }
+                       int n1 = Integer.parseInt(tok.nextToken()) - 1;
+                       int n2 = Integer.parseInt(tok.nextToken()) - 1;
+                       int latency = (int) (Double.parseDouble(tok.nextToken()) * ratio);
+                       E2ENetwork.setLatency(n1, n2, latency);
+                       lc++;
+                       line = in.readLine();
+               } while (line != null);
+               
+               in.close();
+       
+       } catch (IOException e) {
+               System.err.println("KingParser: " + filename + ", line " + lc + ":");
+               e.printStackTrace();
+               try { in.close(); } catch (IOException e1) { };
+               System.exit(1);
+       }
+
+
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/transport/RouterInfo.java b/contrib/psg/src/peersim/transport/RouterInfo.java
new file mode 100644 (file)
index 0000000..be3c168
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.transport;
+
+/**
+ * Generic interface to be implemented by protocols that need to be assigned to
+ * routers. The idea is that each node is assigned to a router, by
+ * invoking {@link #setRouter(int)} method. Routers are identified by
+ * integer indexes (starting from 0), based on the assumption that the
+ * router network
+ * is static. The router information is then used by different 
+ * implementations to compute latency, congestion, etc.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.4 $
+ */
+public interface RouterInfo
+{
+
+/**
+ * Associates the node hosting this transport protocol instance with
+ * a router in the router network.
+ * 
+ * @param router the numeric index of the router 
+ */
+public void setRouter(int router);
+
+/**
+ * @return the router associated to this transport protocol.
+ */
+public int getRouter();
+
+}
diff --git a/contrib/psg/src/peersim/transport/Transport.java b/contrib/psg/src/peersim/transport/Transport.java
new file mode 100644 (file)
index 0000000..4606283
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.transport;
+
+import peersim.core.*;
+
+
+/**
+ * This interface represents a generic transport protocol, used to
+ * send messages through the underlying network. Generally, transport
+ * protocols use {@link peersim.edsim.EDSimulator} to schedule the delivery of
+ * messages with some appropriate delay. They can also model message omission
+ * failure as well.
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.7 $
+ */
+public interface Transport extends Protocol
+{
+       
+/**
+ * Sends message <code>msg</code>      from node <code>src</code> to protocol
+ * <code>pid</code> of node <code>dst</code>.
+ * 
+ * @param src sender node
+ * @param dest destination node
+ * @param msg message to be sent
+ * @param pid protocol identifier
+ */
+public void send(Node src, Node dest, Object msg, int pid);
+
+
+/**
+ * Return a latency estimate from node <code>src</code> to protocol
+ * <code>pid</code> of node <code>dst</code>. 
+ * 
+ * @param src sender node
+ * @param dest destination node
+ */
+public long getLatency(Node src, Node dest);
+
+
+}
diff --git a/contrib/psg/src/peersim/transport/TriangularMatrixParser.java b/contrib/psg/src/peersim/transport/TriangularMatrixParser.java
new file mode 100644 (file)
index 0000000..d3f0768
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.transport;
+
+import java.io.*;
+
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Initializes static singleton {@link E2ENetwork} by reading a trace 
+ * file containing the latency distance measured between a set of 
+ * "virtual" routers. Latency is assumed to be symmetric, so the 
+ * latency between x and y is equal to the latency to y and x.
+ * 
+ * The format of the file is as follows: all values are stored as
+ * integers. The first value is the number of nodes considered.
+ * The rest of the values correspond to a "strictly upper triangular 
+ * matrix" (see this 
+ * <a href="http://en.wikipedia.org/w/index.php?title=Triangular_matrix&oldid=82411128">
+ * link</a>), ordered first by row than by column.
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.4 $
+ */
+public class TriangularMatrixParser implements Control
+{
+
+// ---------------------------------------------------------------------
+// Parameters
+// ---------------------------------------------------------------------
+
+/**
+ * This configuration parameter identifies the filename of the file
+ * containing the measurements. First, the file is used as a pathname 
+ * in the local file system. If no file can be identified in this way, 
+ * the file is searched in the local classpath. If the file cannot be 
+ * identified again, an error message is reported.
+ * @config
+ */
+private static final String PAR_FILE = "file";
+
+/**
+ * The ratio between the time units used in the configuration file and the
+ * time units used in the Peersim simulator.
+ * @config
+ */
+private static final String PAR_RATIO = "ratio";
+
+// ---------------------------------------------------------------------
+// Fields
+// ---------------------------------------------------------------------
+
+/** Name of the file containing the measurements. */
+private String filename;
+
+/** Ratio read from PAR_RATIO */
+private double ratio;
+
+// ---------------------------------------------------------------------
+// Initialization
+// ---------------------------------------------------------------------
+
+/**
+ * Read the configuration parameters.
+ */
+public TriangularMatrixParser(String prefix)
+{
+       filename = Configuration.getString(prefix + "." + PAR_FILE);
+       ratio = Configuration.getDouble(prefix + "." + PAR_RATIO);
+}
+
+// ---------------------------------------------------------------------
+// Methods
+// ---------------------------------------------------------------------
+
+/**
+ * Initializes static singleton {@link E2ENetwork} by reading a king data set.
+* @return  always false
+*/
+public boolean execute()
+{
+       try {
+               ObjectInputStream in = null;
+               try {
+                       in = new ObjectInputStream(
+                                       new BufferedInputStream(
+                                                       new FileInputStream(filename)));
+                       System.err.println("TriangularMatrixParser: Reading " + filename + " from local file system");
+               } catch (FileNotFoundException e) {
+                       in = new ObjectInputStream(
+                                       new BufferedInputStream(
+                                                       ClassLoader.getSystemResourceAsStream(filename)));
+                       System.err.println("TriangularMatrixParser: Reading " + filename + " through the class loader");
+               }
+       
+               // Read the number of nodes in the file (first four bytes).
+         int size = in.readInt();
+         
+               // Reset the E2E network
+               E2ENetwork.reset(size, true);
+               System.err.println("TriangularMatrixParser: reading " + size + " rows");
+       
+               // If the file format is not correct, data will be read 
+               // incorrectly. Probably a good way to spot this is the 
+               // presence of negative delays, or an end of file.
+       
+               // Reading data
+               int count = 0;
+               for (int r=0; r < size; r++) {
+                       for (int c = r+1; c < size; c++) {
+                               int x = (int) (ratio*in.readInt());
+                               count++;
+                               E2ENetwork.setLatency(r,c,x);
+                       }
+               }
+               System.err.println("TriangularMatrixParser: Read " + count + " entries");
+       } catch (IOException e) {
+               throw new RuntimeException(e.getMessage());
+       }
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/transport/UniformRandomTransport.java b/contrib/psg/src/peersim/transport/UniformRandomTransport.java
new file mode 100644 (file)
index 0000000..1abc6d8
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.transport;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.edsim.*;
+
+
+/**
+ * Implement a transport layer that reliably delivers messages with a random
+ * delay, that is drawn from the configured interval according to the uniform
+ * distribution.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.14 $
+ */
+public final class UniformRandomTransport implements Transport
+{
+
+//---------------------------------------------------------------------
+//Parameters
+//---------------------------------------------------------------------
+
+/** 
+ * String name of the parameter used to configure the minimum latency.
+ * @config
+ */    
+private static final String PAR_MINDELAY = "mindelay"; 
+       
+/** 
+ * String name of the parameter used to configure the maximum latency.
+ * Defaults to {@value #PAR_MINDELAY}, which results in a constant delay.
+ * @config 
+ */    
+private static final String PAR_MAXDELAY = "maxdelay"; 
+       
+//---------------------------------------------------------------------
+//Fields
+//---------------------------------------------------------------------
+
+/** Minimum delay for message sending */
+private final long min;
+       
+/** Difference between the max and min delay plus one. That is, max delay is
+* min+range-1.
+*/
+private final long range;
+
+       
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/**
+ * Reads configuration parameter.
+ */
+public UniformRandomTransport(String prefix)
+{
+       min = Configuration.getLong(prefix + "." + PAR_MINDELAY);
+       long max = Configuration.getLong(prefix + "." + PAR_MAXDELAY,min);
+       if (max < min) 
+          throw new IllegalParameterException(prefix+"."+PAR_MAXDELAY, 
+          "The maximum latency cannot be smaller than the minimum latency");
+       range = max-min+1;
+}
+
+//---------------------------------------------------------------------
+
+/**
+* Returns <code>this</code>. This way only one instance exists in the system
+* that is linked from all the nodes. This is because this protocol has no
+* node specific state.
+*/
+public Object clone()
+{
+       return this;
+}
+
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/**
+ * Delivers the message with a random
+ * delay, that is drawn from the configured interval according to the uniform
+ * distribution.
+*/
+public void send(Node src, Node dest, Object msg, int pid)
+{
+       // avoid calling nextLong if possible
+       long delay = (range==1?min:min + CommonState.r.nextLong(range));
+       EDSimulator.add(delay, msg, dest, pid);
+}
+
+/**
+ * Returns a random
+ * delay, that is drawn from the configured interval according to the uniform
+ * distribution.
+*/
+public long getLatency(Node src, Node dest)
+{
+       return (range==1?min:min + CommonState.r.nextLong(range));
+}
+
+
+}
diff --git a/contrib/psg/src/peersim/transport/UniformRouterAssignment.java b/contrib/psg/src/peersim/transport/UniformRouterAssignment.java
new file mode 100644 (file)
index 0000000..064ba7d
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.transport;
+
+import peersim.config.*;
+import peersim.core.*;
+
+
+/**
+ * Initializes {@link RouterInfo} protocols by assigning routers to them.
+ * The number of routers is defined by static singleton {@link E2ENetwork}.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.6 $
+ */
+public class UniformRouterAssignment implements Control
+{
+
+//---------------------------------------------------------------------
+//Parameters
+//---------------------------------------------------------------------
+
+/** 
+ * Parameter name used to configure the {@link RouterInfo} protocol
+ * that should be initialized.
+ * @config 
+ */
+private static final String PAR_PROT = "protocol"; 
+       
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/** Protocol identifier */
+private int pid;       
+       
+
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/**
+ * Reads configuration parameters.
+ */
+public UniformRouterAssignment(String prefix)
+{
+       pid = Configuration.getPid(prefix+"."+PAR_PROT);
+}
+
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/**
+ * Initializes given {@link RouterInfo} protocol layer by assigning
+ * routers randomly.
+ * The number of routers is defined by static singleton {@link E2ENetwork}.
+* @return always false
+*/
+public boolean execute()
+{
+       int nsize = Network.size();
+       int nrouters = E2ENetwork.getSize();
+       for (int i=0; i < nsize; i++) {
+               Node node = Network.get(i);
+               RouterInfo t = (RouterInfo) node.getProtocol(pid);
+               int r = CommonState.r.nextInt(nrouters);
+               t.setRouter(r);
+       }
+
+       return false;
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/transport/UnreliableTransport.java b/contrib/psg/src/peersim/transport/UnreliableTransport.java
new file mode 100644 (file)
index 0000000..9460880
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.transport;
+
+import peersim.config.*;
+import peersim.core.*;
+
+
+/**
+ * This transport protocol can be combined with other transports
+ * to simulate message losses. Its behavior is the following: each message
+ * can be dropped based on the configured probability, or it will be sent
+ * using the underlying transport protocol. 
+ * <p>
+ * The memory requirements are minimal, as a single instance is created and 
+ * inserted in the protocol array of all nodes (because instances have no state
+ * that depends on the hosting node). 
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.13 $
+ */
+public final class UnreliableTransport implements Transport
+{
+
+//---------------------------------------------------------------------
+//Parameters
+//---------------------------------------------------------------------
+
+/**
+ * The name of the underlying transport protocol. This transport is
+ * extended with dropping messages.
+ * @config
+ */
+private static final String PAR_TRANSPORT = "transport";
+
+/** 
+ * String name of the parameter used to configure the probability that a 
+ * message sent through this transport is lost.
+ * @config
+ */
+private static final String PAR_DROP = "drop";
+
+
+//---------------------------------------------------------------------
+//Fields
+//---------------------------------------------------------------------
+
+/** Protocol identifier for the support transport protocol */
+private final int transport;
+
+/** Probability of dropping messages */
+private final float loss;
+
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/**
+ * Reads configuration parameter.
+ */
+public UnreliableTransport(String prefix)
+{
+       transport = Configuration.getPid(prefix+"."+PAR_TRANSPORT);
+       loss = (float) Configuration.getDouble(prefix+"."+PAR_DROP);
+}
+
+//---------------------------------------------------------------------
+
+/**
+* Returns <code>this</code>. This way only one instance exists in the system
+* that is linked from all the nodes. This is because this protocol has no
+* state that depends on the hosting node.
+ */
+public Object clone()
+{
+       return this;
+}
+
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/** Sends the message according to the underlying transport protocol.
+* With the configured probability, the message is not sent (i.e. the method does
+* nothing).
+*/
+public void send(Node src, Node dest, Object msg, int pid)
+{
+       try
+       {
+               if (CommonState.r.nextFloat() >= loss)
+               {
+                       // Message is not lost
+                       Transport t = (Transport) src.getProtocol(transport);
+                       t.send(src, dest, msg, pid);
+               }
+       }
+       catch(ClassCastException e)
+       {
+               throw new IllegalArgumentException("Protocol " +
+                               Configuration.lookupPid(transport) + 
+                               " does not implement Transport");
+       }
+}
+
+/** Returns the latency of the underlying protocol.*/
+public long getLatency(Node src, Node dest)
+{
+       Transport t = (Transport) src.getProtocol(transport);
+       return t.getLatency(src, dest);
+}
+
+}
diff --git a/contrib/psg/src/peersim/util/ExtendedRandom.java b/contrib/psg/src/peersim/util/ExtendedRandom.java
new file mode 100644 (file)
index 0000000..14e713e
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.util;
+
+import java.util.Random;
+import java.lang.Math;
+
+/**
+ * Extends the functionality of <code>java.util.Random</code>.
+ */
+public class ExtendedRandom extends Random {
+
+private long lastSeed;
+
+// -------------------------------------------------------------------------
+
+/** Calls super constructor. Also stores the seed to be returned by
+{@link #getLastSeed}. */
+public ExtendedRandom(long seed) {
+       
+       super(seed);
+       lastSeed = seed;
+}
+
+// -------------------------------------------------------------------------
+
+/**
+ * Extracts the next integer, according to a Poisson distribution.
+ * 
+ * @param mean The mean of the Poisson distribution.
+ * @return An integer Poisson extraction.
+ */
+public int nextPoisson(double mean) {
+       
+       double emean = Math.exp(-1 * mean);
+       double product = 1;
+       int count = 0;
+       int result = 0;
+       while (product >= emean) {
+               product *= nextDouble();
+               result = count;
+               count++; // keep result one behind
+       }
+       return result;
+}
+
+// -------------------------------------------------------------------------
+
+/**
+* Implements nextLong(long) the same way nexInt(int) is implemented in
+* java.util.Random.
+* @param n the bound on the random number to be returned. Must be positive.
+* @return a pseudorandom, uniformly distributed long value between 0
+* (inclusive) and n (exclusive).
+*/
+public long nextLong(long n) {
+
+       if (n<=0)
+               throw new IllegalArgumentException("n must be positive");
+       
+       if ((n & -n) == n)  // i.e., n is a power of 2
+       {       
+               return nextLong()&(n-1);
+       }
+       
+       long bits, val;
+       do
+       {
+               bits = (nextLong()>>>1);
+               val = bits % n;
+       }
+       while(bits - val + (n-1) < 0);
+       
+       return val;
+}
+
+// -------------------------------------------------------------------------
+
+/** Sets random seed. Calls super method but also stores the seed to be
+returned by {@link #getLastSeed}. */
+public void setSeed( long seed ) {
+       
+       super.setSeed(seed);
+       lastSeed = seed;
+}
+
+// -------------------------------------------------------------------------
+
+/**
+* Returns the last random seed that was set explicitly. Either at
+* construction time or through {@link #setSeed}.
+*/
+public long getLastSeed() { return lastSeed; }
+
+// -------------------------------------------------------------------------
+
+/*
+public static void main(String[] args) {
+
+       ExtendedRandom er = new ExtendedRandom(12345678);
+       for(int i=0; i<100; ++i)
+               System.out.println(er.nextLong(Long.parseLong(args[0])));
+       
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/util/FileNameGenerator.java b/contrib/psg/src/peersim/util/FileNameGenerator.java
new file mode 100644 (file)
index 0000000..c07d925
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.util;
+
+import java.io.*;
+
+
+/**
+* Generates a series of filenames for classes that have to save e.g.
+* snapshots regularly.
+*/
+public class FileNameGenerator {
+
+
+/**
+* The number of filenames already returned.
+*/
+private long counter = 0;
+
+/** The prefix of the filename */
+public final String prefix;
+
+/** The extension of the filename */
+public final String ext;
+
+
+// ==================== initialization ==============================
+// ==================================================================
+
+
+/**
+* @param prefix all returned names will be prefixed by this
+* @param ext will be appended to all returned names
+*/
+public FileNameGenerator(String prefix, String ext) {
+       
+       this.prefix=prefix;
+       this.ext=ext;
+}
+
+
+// ===================== methods ====================================
+// ==================================================================
+
+
+/**
+* Generates a name based on a counter.
+* The format of the name returned is {@link #prefix} followed by
+* an 8 digit zero padded number, followed by {@link #ext}.
+* The first number used is zero.
+* @return the next filename after increasing the counter
+*/
+public String nextCounterName() {
+       
+       ByteArrayOutputStream baos = new ByteArrayOutputStream();
+       (new PrintStream(baos)).printf("%08d",counter);
+       counter++;
+       return prefix+baos.toString()+ext;
+}
+
+// ------------------------------------------------------------------
+
+/*
+public static void main(String args[]) {
+       
+       FileNameGenerator fng = new FileNameGenerator(args[0],args[1]);
+       for(int i=0; i<100; ++i) System.err.println(fng.nextCounterName()); 
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/util/IncrementalFreq.java b/contrib/psg/src/peersim/util/IncrementalFreq.java
new file mode 100644 (file)
index 0000000..3352daf
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.util;
+
+import java.io.PrintStream;
+
+//XXX This implementation is very restricted, to be made more flexible
+// using hashtables.
+/**
+* A class that can collect frequency information on integer input.
+* right now it can handle only unsigned input. It simply ignores negative
+* numbers.
+*/
+public class IncrementalFreq implements Cloneable {
+
+
+// ===================== fields ========================================
+// =====================================================================
+
+/** The number of items inserted. */
+private int n;
+
+/** freq[i] holds the frequency of i. primitive implementation, to be changed */
+private int[] freq = null; 
+
+/**
+* The capacity, if larger than 0. Added values larger than or equal to
+* this one will be ignored.
+*/
+private final int N;
+
+
+// ====================== initialization ==============================
+// ====================================================================
+
+
+/**
+* @param maxvalue Values in the input set larger than this one will be ignored.
+* However, if it is negative, no values are ignored.
+*/
+public IncrementalFreq(int maxvalue) {
+       
+       N = maxvalue+1;
+       reset();
+}
+
+// --------------------------------------------------------------------
+
+/** Calls <code>this(-1)</code>, that is, no values will be ignored.
+* @see #IncrementalFreq(int) */
+public IncrementalFreq() {
+       
+       this(-1);
+}
+
+// --------------------------------------------------------------------
+
+/** Reset the state of the object. After calling this, all public methods
+* behave the same as they did after constructing the object.
+*/
+public void reset() {
+
+       if( freq==null || N==0 ) freq = new int[0];
+       else for(int i=0; i<freq.length; ++i) freq[i]=0;
+       n = 0;
+}
+
+
+// ======================== methods ===================================
+// ====================================================================
+
+/**
+ * Adds item <code>i</code> to the input set.
+ * It calls <code>add(i,1)</code>.
+ * @see #add(int,int)
+ */
+public final void add( int i ) { add(i,1); }
+
+
+// --------------------------------------------------------------------
+
+/**
+ * Adds item <code>i</code> to the input set <code>k</code> times.
+ * That is, it increments counter <code>i</code> by <code>k</code>.
+ * If, however, <code>i</code> is negative, or larger than the maximum defined
+ * at construction time (if a maximum was set at all) the operation is ignored.
+ */
+public void add( int i, int k ) {
+  
+  if( N>0 && i>=N ) return;
+  if( i<0 || k<=0 ) return;
+
+  // Increase number of items by k.
+  n+=k;
+
+  // If index i is out of bounds for the current array of counters,
+  // increase the size of the array to i+1.
+  if( i>=freq.length )
+  {
+    int tmp[] = new int[i+1];
+    System.arraycopy(freq, 0, tmp, 0, freq.length);
+    freq=tmp;
+  }
+
+  // Finally, increase counter i by k.
+  freq[i]+=k;
+}
+
+// --------------------------------------------------------------------
+
+/** Returns number of processed data items.
+* This is the number of items over which the class holds statistics.
+*/
+public int getN() { return n; }
+
+// --------------------------------------------------------------------
+
+/** Returns the number of occurrences of the given integer. */
+public int getFreq(int i) {
+       
+       if( i>=0 && i<freq.length ) return freq[i];
+       else return 0;
+}
+
+// --------------------------------------------------------------------
+       
+
+/**
+ * Performs an element-by-element vector subtraction of the
+ * frequency vectors. If <code>strict</code> is true, it
+ * throws an IllegalArgumentException if <code>this</code> is
+ * not strictly larger than <code>other</code> (element by element)
+ * (Note that both frequency vectors are positive.)
+ * Otherwise just sets those elements in <code>this</code> to zero
+ * that are smaller than those of <code>other</code>.
+ * @param other The instance of IncrementalFreq to subtract
+ * @param strict See above explanation
+ */
+public void remove(IncrementalFreq other, boolean strict) {
+
+       // check if other has non-zero elements in non-overlapping part
+       if(strict && other.freq.length>freq.length)
+       {
+               for(int i=other.freq.length-1; i>=freq.length; --i)
+               {
+                       if (other.freq[i]!=0)
+                               throw new IllegalArgumentException();
+               }
+       }
+       
+       final int minLength = Math.min(other.freq.length, freq.length);
+       for (int i=minLength-1; i>=0; i--)
+       {
+               if (strict && freq[i] < other.freq[i])
+                       throw new IllegalArgumentException();
+               final int remove = Math.min(other.freq[i], freq[i]);
+               n -= remove;
+               freq[i] -= remove;
+       }
+}
+
+// ---------------------------------------------------------------------
+
+/**
+* Prints current frequency information. Prints a separate line for
+* all values from 0 to the capacity of the internal representation using the
+* format
+* <pre>
+* value occurrences
+* </pre>
+* That is, numbers with zero occurrences will also be printed. 
+*/
+public void printAll( PrintStream out ) {
+       
+       for(int i=0; i<freq.length; ++i)
+       {
+               out.println(i+" "+freq[i]);
+       }
+}
+
+// ---------------------------------------------------------------------
+
+/**
+* Prints current frequency information. Prints a separate line for
+* all values that have a number of occurrences different from zero using the 
+* format
+* <pre>
+* value occurrences
+* </pre>
+*/
+public void print( PrintStream out ) {
+
+       for(int i=0; i<freq.length; ++i)
+       {
+               if(freq[i]!=0) out.println(i+" "+freq[i]);
+       }
+}
+
+// ---------------------------------------------------------------------
+
+public String toString() {
+       
+       StringBuilder result=new StringBuilder("");
+       for(int i=0; i<freq.length; ++i)
+       {
+               if (freq[i] != 0)
+                       result.append(" (").append(i).append(","
+                       ).append(freq[i]).append(")");
+       }
+       return result.toString();
+}
+
+// ---------------------------------------------------------------------
+
+/** An alternative method to convert the object to String */
+public String toArithmeticExpression() {
+
+       StringBuilder result=new StringBuilder("");
+       for (int i=freq.length-1; i>=0; i--)
+       {
+               if (freq[i] != 0)
+                       result.append(freq[i]).append(
+                       "*").append(i).append("+");
+       }
+       
+       if (result.length()==0)
+               return "(empty)";
+       else
+               return result.substring(0, result.length()-1);
+}
+
+// ---------------------------------------------------------------------
+
+public Object clone() throws CloneNotSupportedException {
+
+       IncrementalFreq result = (IncrementalFreq)super.clone();
+       if( freq != null ) result.freq = freq.clone();
+       return result;
+}
+
+// ---------------------------------------------------------------------
+
+/**
+* Tests equality between two IncrementalFreq instances.
+* Two objects are equal if both hold the same set of numbers that have
+* occurred non-zero times and the number of occurrences is also equal for
+* these numbers.
+*/
+public boolean equals(Object obj) {
+
+       if( !( obj instanceof IncrementalFreq) ) return false;
+       IncrementalFreq other = (IncrementalFreq)obj;
+       final int minlength = Math.min(other.freq.length, freq.length);
+       
+       for (int i=minlength-1; i>=0; i--)
+               if (freq[i] != other.freq[i])
+                       return false;
+
+       if( freq.length > minlength ) other=this;
+       for (int i=minlength; i<other.freq.length; i++)
+               if( other.freq[i] != 0 )
+                       return false;
+
+       return true;
+}
+
+// ---------------------------------------------------------------------
+
+/**
+* Hashcode (consistent with {@link #equals}). Probably you will never want to
+* use this, but since we have {@link #equals}, we must implement it.
+*/
+public int hashCode() {
+
+       int sum = 0;
+       for(int i=0; i<freq.length; ++i) sum += freq[i]*i;
+       return sum;
+}
+
+// ---------------------------------------------------------------------
+
+/*
+public static void main(String[] pars) {
+       
+       IncrementalFreq ifq = new IncrementalFreq(Integer.parseInt(pars[0]));
+       for(int i=1; i<pars.length; ++i)
+       {
+               ifq.add(Integer.parseInt(pars[i]));
+       }
+       ifq.print(System.out);
+       System.out.println(ifq);
+}
+*/
+}
+
+
diff --git a/contrib/psg/src/peersim/util/IncrementalStats.java b/contrib/psg/src/peersim/util/IncrementalStats.java
new file mode 100644 (file)
index 0000000..eb48d69
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.util;
+
+/**
+* A class that can keep track of some statistics like variance, average, min,
+* max incrementally. That is, when adding a new data item, it updates the
+* statistics.
+*/
+public class IncrementalStats {
+
+
+// ===================== fields ========================================
+// =====================================================================
+
+
+private double min;
+
+private double max;
+
+private double sum;
+
+private double sqrsum;
+
+private int n;
+
+private int countmin;
+
+private int countmax;
+
+// ====================== initialization ==============================
+// ====================================================================
+
+
+/** Calls {@link #reset}. */
+public IncrementalStats() { reset(); }
+
+// --------------------------------------------------------------------
+
+/** Resets the statistics to reflect the zero elements set.
+* Min and max are set to positive and negative infinity, respectively.
+*/
+public void reset() {
+       
+       countmin=0;
+       countmax=0;
+       min = Double.POSITIVE_INFINITY;
+       max = Double.NEGATIVE_INFINITY;
+       sum = 0.0;
+       sqrsum = 0.0;
+       n = 0;
+}
+
+
+// ======================== methods ===================================
+// ====================================================================
+
+
+/** Updates the statistics according to this element. It calls
+* <code>add(item,1)</code>.
+* @see #add(double,int) */
+public final void add( double item ) { add(item,1); }
+
+// --------------------------------------------------------------------
+
+/** Updates the statistics assuming element <code>item</code> is added
+* <code>k</code> times.*/
+public void add( double item, int k ) {
+       
+       if( item < min )
+       {
+               min = item;
+               countmin = 0;
+       } 
+       if( item == min ) countmin+=k;
+       if( item > max )
+       {
+               max = item;
+               countmax = 0;
+       }
+       if(item == max) countmax+=k;  
+       n+=k;
+       if( k == 1 )
+       {
+               sum += item;
+               sqrsum += item*item;
+       }
+       else
+       {
+               sum += item*k;
+               sqrsum += item*item*k;
+       }
+}
+
+// --------------------------------------------------------------------
+
+/** The number of data items processed so far */
+public int getN() { return n; }
+
+// --------------------------------------------------------------------
+
+/** The maximum of the data items */
+public double getMax() { return max; }
+
+// --------------------------------------------------------------------
+
+/** The minimum of the data items */
+public double getMin() { return min; }
+
+// --------------------------------------------------------------------
+
+/** Returns the number of data items whose value equals the maximum. */
+public int getMaxCount() { return countmax; }
+
+// --------------------------------------------------------------------
+
+/** Returns the number of data items whose value equals the minimum. */
+public int getMinCount() { return countmin; }
+
+// --------------------------------------------------------------------
+
+/** The sum of the data items */
+public double getSum() { return sum; }
+
+// --------------------------------------------------------------------
+
+/** The sum of the squares of the data items */
+public double getSqrSum() { return sqrsum; }
+
+// --------------------------------------------------------------------
+
+/** The average of the data items */
+public double getAverage() { return sum/n; }
+
+// --------------------------------------------------------------------
+
+/** The empirical variance of the data items. Guaranteed to be larger or
+equal to 0.0. If due to rounding errors the value becomes negative,
+it returns 0.0.*/
+public double getVar() {
+
+       double var=
+               (((double)n) / (n-1)) * (sqrsum/n - getAverage()*getAverage());
+       return (var>=0.0?var:0.0);
+       // XXX note that we have very little possibility to increase numeric
+       // stability if this class is "greedy", ie, if it has no memory
+       // In a more precise implementation we could delay the calculation of
+       // statistics and store the data in some intelligent structure
+}
+
+// --------------------------------------------------------------------
+
+/** the empirical standard deviation of the data items */
+public double getStD() { return Math.sqrt(getVar()); }
+
+// --------------------------------------------------------------------
+
+/**
+* Prints the following quantities separated by spaces in a single line
+* in this order.
+* Minimum, maximum, number of items, average, variance, number of minimal
+* items, number of maximal items.
+*/
+public String toString() {
+
+       return min+" "+max+" "+n+" "+sum/n+" "+getVar()+" "+
+               countmin+" "+countmax;
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/util/IndexIterator.java b/contrib/psg/src/peersim/util/IndexIterator.java
new file mode 100644 (file)
index 0000000..8d078ab
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.util;
+
+/**
+* This class provides iterations over the set of integers [0...k-1].
+*/
+public interface IndexIterator {
+
+       /**
+       * This resets the iteration. The set of integers will be 0,..,k-1.
+       */
+       public void reset(int k);
+       
+       /**
+       * Returns next index.
+       */
+       public int next();
+
+       /**
+       * Returns true if {@link #next} can be called at least one more time.
+       * Note that {@link #next} can be called k times after {@link #reset}.
+       */
+       public boolean hasNext();
+}
+
diff --git a/contrib/psg/src/peersim/util/LinearIterator.java b/contrib/psg/src/peersim/util/LinearIterator.java
new file mode 100644 (file)
index 0000000..2a1ee36
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.util;
+
+import java.util.NoSuchElementException;
+
+/**
+* This class gives the linear order 0,1,etc or alternatively k-1, k-2, etc.,
+* depending on the constructor.
+*/
+public class LinearIterator implements IndexIterator {
+
+
+// ======================= private fields ============================
+// ===================================================================
+
+private final boolean reverse;
+
+private int len = 0;
+
+private int pointer = 0;
+
+
+// ======================= initialization ============================
+// ===================================================================
+
+
+/**
+* Construct an iterator for an empty set of numbers.
+* You have to call {@link #reset} to actually fully initialize the object.
+* The numbers returned by consecutive calls to {@link #next} are 0,1,...
+*/
+public LinearIterator() { reverse=false; }
+
+// -------------------------------------------------------------------
+
+/**
+* Construct an interator for an empty set of numbers.
+* You have to call {@link #reset} to actually fully initialize the object.
+* If parameter is true then the numbers returned by consecutive calls to
+* {@link #next} are k-1,k-2,..., otherwise 0,1,...
+*/
+public LinearIterator( boolean rev ) { reverse=rev; }
+
+
+// ======================= public methods ============================
+// ===================================================================
+
+
+public void reset(int k) {
+       
+       len = k;
+       pointer = (reverse ? len-1 : 0);
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Returns next index. The indices are returned in increasing or decreasing
+* order depending on the parameter given at construction time.
+*/
+public int next() {
+       
+       if( !hasNext() ) throw new NoSuchElementException();
+       
+       return (reverse ? pointer-- : pointer++);
+}
+
+// -------------------------------------------------------------------
+
+public boolean hasNext() { return (reverse ? pointer >= 0 : pointer < len); }
+
+// -------------------------------------------------------------------
+
+/*
+public static void main( String pars[] ) throws Exception {
+       
+       LinearIterator rp = new LinearIterator(pars[0].equals("rev"));
+       
+       int k = Integer.parseInt(pars[1]);
+       rp.reset(k);
+       while(rp.hasNext()) System.out.println(rp.next());
+       
+       System.out.println();
+
+       k = Integer.parseInt(pars[2]);
+       rp.reset(k);
+       while(rp.hasNext()) System.out.println(rp.next());
+       System.out.println(rp.next());
+}
+*/
+}
diff --git a/contrib/psg/src/peersim/util/MedianStats.java b/contrib/psg/src/peersim/util/MedianStats.java
new file mode 100644 (file)
index 0000000..be1e9be
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * This class adds the ability to retrieve the median element to the
+ * {@link IncrementalStats} class. Note that this class actually stores all
+ * the elements, so (unlike in its superclass) storage requirements depend
+ * on the number of items processed.
+ * 
+ * @author giampa
+ */
+public class MedianStats extends IncrementalStats
+{
+
+/** Structure to store each entry. */
+private final ArrayList<Double> data=new ArrayList<Double>();
+
+/** Calls {@link #reset}. */
+public MedianStats()
+{
+       reset();
+}
+
+/**
+ * Retrieves the median in the current data collection.
+ * 
+ * @return The current median value.
+ */
+public double getMedian()
+{
+       double result;
+
+       if (data.isEmpty())
+               throw new IllegalStateException("Data vector is empty!");
+
+       // Sort the arraylist
+       Collections.sort(data);
+       if (data.size() % 2 != 0) { // odd number
+               result = data.get(data.size() / 2);
+       } else { // even number:
+               double a = data.get(data.size() / 2);
+               double b = data.get(data.size() / 2 - 1);
+               result = (a + b) / 2;
+       }
+       return result;
+}
+
+public void add(double item, int k)
+{
+       for (int i = 0; i < k; ++i) {
+               super.add(item, 1);
+               data.add(new Double(item));
+       }
+}
+
+public void reset()
+{
+       super.reset();
+       if (data != null)
+               data.clear();
+}
+
+
+public static void main( String[] args ) {
+       MedianStats s = new MedianStats();
+       for(int i=0; i<args.length; i++) s.add(Double.parseDouble(args[i]));
+       System.out.println("Average: "+s.getAverage());
+       System.out.println("Median: "+s.getMedian());
+}
+
+}
diff --git a/contrib/psg/src/peersim/util/MomentStats.java b/contrib/psg/src/peersim/util/MomentStats.java
new file mode 100644 (file)
index 0000000..0a847c3
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.util;
+
+/**
+ * This class provides extended statistical informations about the inspected 
+ * distribution. In particular, it provides functions to compute the skewness
+ * (the 3rd degree moment) and the kurtosis (4th degree moment).
+ *
+ * @author  Gian Paolo Jesi
+ */
+public class MomentStats extends IncrementalStats {
+    
+    private double cubicsum, quadsum; // incremental sums
+    
+    /** Calls {@link #reset} */
+    public MomentStats() {
+       reset();
+    }
+    
+    public void reset() {
+        super.reset();
+        cubicsum = quadsum = 0.0;
+    }
+    
+    public void add(double item, int k) {
+        for(int i=0; i<k; ++i)
+       {
+               super.add(item,1);
+               cubicsum += item * item * item;
+               quadsum += item * cubicsum;
+       }
+    }
+   
+    /** Outputs on a single line the superclass statistics postfixed by the 
+     * current skewness and kurtosis.
+     */
+    public String toString() {
+        return super.toString()+" "+getSkewness()+" "+getKurtosis();
+    }
+    
+    /** Computes the skewness on the node values distribution and 
+     * returns the asymmetry coefficient. It gives an indication about the 
+     * distribution symmetry compared to the average.
+     *
+     *@return The skewness value as a double.
+     */ 
+    public double getSkewness() {
+        int n = this.getN();
+        double m3 = (((double)n) / (n-1)) * (cubicsum/n - Math.pow(getAverage(), 3) );
+        return ( m3 / Math.pow(getStD(), 3 ) );
+    }
+    
+    /** Computes the kurtosis on the node values distribution and 
+     *  returns the flatness coefficient. It gives an indication about the 
+     *  distribution sharpness or flatness.
+     *
+     * @return The kurtosis momentus value as a double.
+     */ 
+    public double getKurtosis(){
+        int n = this.getN();
+        double m4 = (((double)n) / (n-1)) * (quadsum/n - Math.pow(getAverage(), 4) );
+        return ( m4 / Math.pow(getStD(), 4) )-3;
+    }
+
+}
diff --git a/contrib/psg/src/peersim/util/RandPermutation.java b/contrib/psg/src/peersim/util/RandPermutation.java
new file mode 100644 (file)
index 0000000..be97ab3
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.util;
+
+import java.util.NoSuchElementException;
+import java.util.Random;
+
+/**
+* This class provides a random permutation of indexes. Useful for
+* random sampling without replacement.
+*/
+public class RandPermutation implements IndexIterator {
+
+
+// ======================= private fields ============================
+// ===================================================================
+
+
+private int[] buffer = null;
+
+private int len = 0;
+
+private int pointer = 0;
+
+private final Random r;
+
+
+// ======================= initialization ============================
+// ===================================================================
+
+
+/** Sets source of randomness to be used. You need to call
+* {@link #reset} to fully initialize the object.
+* @param r Source of randomness
+*/
+public RandPermutation( Random r ) { this.r=r; }
+
+// -------------------------------------------------------------------
+
+/** Sets source of randomness and initial size. It calls 
+* {@link #setPermutation} to fully initialize the object with a
+* permuation ready to use. 
+* @param r Source of randomness
+* @param k size of permutation
+*/
+public RandPermutation( int k, Random r ) {
+       
+       this.r=r;
+       setPermutation(k);
+}
+
+
+// ======================= public methods ============================
+// ===================================================================
+
+
+/**
+* It calculates a random permutation of the integers from 0 to k-1.
+* The permutation can be read using method {@link #get}. 
+* If the previous permutation was of the same length, it is more efficient.
+* Note that after calling this the object is reset, so {@link #next} can
+* be called k times, even if {@link #get} was called an arbitrary number of
+* times. Note however that mixing {@link #get} and {@link #next} results in
+* incorrect behavior for {@link #get} (but {@link #next} works fine).
+* The idea is to use this method only in connection with {@link #get}.
+*/
+public void setPermutation(int k) {
+       
+       reset(k);
+       
+       for(int i=len; i>1; i--)
+       {
+               int j = r.nextInt(i);
+               int a = buffer[j];
+               buffer[j] = buffer[i-1];
+               buffer[i-1] = a;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Returns the ith element of the permutation set by {@link #setPermutation}.
+* If {@link #next} is called after {@link #setPermutation} and before
+* this method, then the behavior of this method is unspecified.
+*/
+public int get(int i) {
+       
+       if( i >= len ) throw new IndexOutOfBoundsException();
+       return buffer[i];
+}
+
+// -------------------------------------------------------------------
+
+/**
+* It initiates a random permutation of the integers from 0 to k-1.
+* It does not actually calculate the permutation.
+* The permutation can be read using method {@link #next}.
+* Calls to {@link #get} return undefined values, so {@link #next} must be used.
+* If the previous permutation was of the same length, it is more efficient.
+*/
+public void reset(int k) {
+       
+       pointer = k;
+       if( len == k ) return;
+       
+       if( buffer == null || buffer.length < k )
+       {
+               buffer = new int[k];
+       }
+       
+       len = k;
+       for( int i=0; i<len; ++i ) buffer[i]=i;
+}
+
+// -------------------------------------------------------------------
+
+/** Next random sample without replacement */
+public int next() {
+       
+       if( pointer < 1 ) throw new NoSuchElementException();
+       
+       int j = r.nextInt(pointer);
+       int a = buffer[j];
+       buffer[j] = buffer[pointer-1];
+       buffer[pointer-1] = a;
+       
+       return buffer[--pointer];
+}
+
+// -------------------------------------------------------------------
+
+public boolean hasNext() { return pointer > 0; }
+
+// -------------------------------------------------------------------
+
+/*
+public static void main( String pars[] ) throws Exception {
+       
+       RandPermutation rp = new RandPermutation(new Random());
+
+       int k;
+       
+       k = Integer.parseInt(pars[0]);
+       rp.setPermutation(k);
+       for(int i=0; i<k; ++i) System.out.println(rp.get(i));
+
+       System.out.println();
+
+       k = Integer.parseInt(pars[1]);
+       rp.reset(k);
+       while(rp.hasNext()) System.out.println(rp.next());
+       
+       System.out.println();
+
+       k = Integer.parseInt(pars[2]);
+       rp.reset(k);
+       while(rp.hasNext()) System.out.println(rp.next());
+       System.out.println(rp.next());
+}
+*/
+}
diff --git a/contrib/psg/src/peersim/util/StringListParser.java b/contrib/psg/src/peersim/util/StringListParser.java
new file mode 100644 (file)
index 0000000..445e19f
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.util;
+
+import java.math.*;
+import java.util.*;
+
+import org.lsmp.djep.groupJep.*;
+
+import peersim.config.*;
+
+/**
+ * This utility class can be used to parse range expressions. In particular,
+ * it is used by {@link peersim.rangesim.RangeSimulator} to express ranges for
+ * configuration properties.
+ * <p>
+ * The language for range expression is the following: 
+ * <pre>
+ *   [rangelist] := [range] | [range],[rangelist]
+ *   [range] := value | min:max | min:max|step | 
+ *      min:max*|step
+ * </pre>
+ * where <tt>value</tt>, <tt>min</tt>, <tt>max</tt> and <tt>step</tt>
+ * are numeric atoms that defines ranges.
+ * <p>
+ * For example, the following range expression:
+ * <pre>
+ *   5,9:11,13:17|2,32:128*|2
+ * </pre>
+ * corresponds to 5 (single value), 9-10-11 (range between 9 and 11,
+ * default increment 1), 13-15-17 (range between 13 and 17, specified
+ * step 2, 32-64-128 (range between 32 and 128, multiplicative step 2).
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.8 $
+ */
+public class StringListParser
+{
+
+/** Disable instance construction */
+private StringListParser() { }
+
+/**
+ * Parse the specified string.
+ * 
+ * @param s the string to be parsed
+ * @return an array of strings containing all the values defined by the
+ *   range string
+ */
+public static String[] parseList(String s)
+{
+       ArrayList<String> list = new ArrayList<String>();
+       String[] tokens = s.split(",");
+       for (int i = 0; i < tokens.length; i++) {
+               parseItem(list, tokens[i]);
+       }
+       return list.toArray(new String[list.size()]);
+}
+
+private static void parseItem(List<String> list, String item)
+{
+       String[] array = item.split(":");
+       if (array.length == 1) {
+               parseSingleItem(list, item);
+       } else if (array.length == 2) {
+               parseRangeItem(list, array[0], array[1]);
+       } else {
+               throw new IllegalArgumentException("Element " + item
+                               + "should be formatted as <start>:<stop> or <value>");
+       }
+}
+
+private static void parseSingleItem(List<String> list, String item)
+{
+       list.add(item);
+}
+
+private static void parseRangeItem(List<String> list, String start, String stop)
+{
+       Number vstart;
+       Number vstop;
+       Number vinc;
+       boolean sum;
+       
+       GroupJep jep = new GroupJep(new Operators());
+       jep.parseExpression(start);
+       vstart = (Number) jep.getValueAsObject(); 
+       int pos = stop.indexOf("|*");
+       if (pos >= 0) {
+               // The string contains a multiplicative factor
+               jep.parseExpression(stop.substring(0, pos));
+               vstop = (Number) jep.getValueAsObject(); 
+               jep.parseExpression(stop.substring(pos + 2));
+               vinc = (Number) jep.getValueAsObject(); 
+               sum = false;
+       } else {
+               pos = stop.indexOf("|");
+               // The string contains an additive factor
+               if (pos >= 0) {
+                       // The string contains just the final value
+                       jep.parseExpression(stop.substring(0, pos));
+                       vstop = (Number) jep.getValueAsObject(); 
+                       jep.parseExpression(stop.substring(pos + 1));
+                       vinc = (Number) jep.getValueAsObject(); 
+                       sum = true;
+               } else {
+                       jep.parseExpression(stop);
+                       vstop = (Number) jep.getValueAsObject(); 
+                       vinc = BigInteger.ONE;
+                       sum = true;
+               }
+       }
+       
+       if (vstart instanceof BigInteger && vstart instanceof BigInteger && vinc instanceof BigInteger) {
+               long vvstart = vstart.longValue();
+               long vvstop  =  vstop.longValue();
+               long vvinc   =   vinc.longValue(); 
+               if (sum) {
+                       for (long i = vvstart; i <= vvstop; i += vvinc)
+                               list.add("" + i);
+               } else {
+                       for (long i = vvstart; i <= vvstop; i *= vvinc)
+                               list.add("" + i);
+               }
+       } else {
+               double vvstart = vstart.doubleValue();
+               double vvstop  =  vstop.doubleValue();
+               double vvinc   =   vinc.doubleValue(); 
+               if (sum) {
+                       for (double i = vvstart; i <= vvstop; i += vvinc) 
+                               list.add("" + i);
+               } else {
+                       for (double i = vvstart; i <= vvstop; i *= vvinc)
+                               list.add("" + i);
+               }
+       }
+}
+
+/*
+public static void main(String[] args)
+{
+       String[] ret = parseList(args[0]);
+       for (int i = 0; i < ret.length; i++)
+               System.out.print(ret[i] + " ");
+       System.out.println("");
+}
+*/
+}
diff --git a/contrib/psg/src/peersim/util/WeightedRandPerm.java b/contrib/psg/src/peersim/util/WeightedRandPerm.java
new file mode 100644 (file)
index 0000000..80c8928
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.util;
+
+import java.util.NoSuchElementException;
+import java.util.Random;
+
+/**
+* This class provides a weighted random permutation of indexes.
+* Useful for weighted random sampling without replacement.
+* The next sample is taken according to the weights given as a parameter
+* to {@link #reset(int)}.
+* The weights work as follows.
+* The first sample is drawn according to the probability distribution
+* defined by the (normalized) weights.
+* After this the remaining k-1 elements and the associated k-1
+* (re-normalized) weights
+* define a new probability distribution, according to which the 2nd element
+* is drawn, and so on.
+*/
+public class WeightedRandPerm implements IndexIterator {
+
+
+// ======================= private fields ============================
+// ===================================================================
+
+/** Holds the weights that are used to initialize the permutation */
+private final double[] w;
+
+/** Holds the sum of the weights until the given index, inclusive. */
+private final double[] wsum;
+
+private int[] buffer = null;
+
+/** Working array for calculating the permutation */ 
+private double[] weights = null;
+
+private int len = 0;
+
+private int pointer = 0;
+
+private double sum = 0.0;
+
+private final Random r;
+
+
+// ======================= initialization ============================
+// ===================================================================
+
+
+/** Set the source of randomness to use and the weights. You need to call
+* {@link #reset} to fully initialize the object.
+* @param r source of randomness
+* @param weights The array that holds the weights for the calculation of the
+* permutation. The length of the array will be an upper bound on the
+* parameter {@link #reset} accepts. If {@link #reset} is called with a
+* parameter less than the length of weights, the prefix of the same length
+* is used.
+* The vector elements must be positive, that is, zero is not accepted either.
+*/
+public WeightedRandPerm( Random r, double[] weights ) {
+
+       this.r=r;
+       w = weights.clone();
+       wsum = weights.clone();;
+       this.weights = new double[w.length];
+       buffer = new int[w.length];
+       
+       for(int i=0; i<w.length; ++i)
+       {
+               if( w[i] <= 0.0 ) throw new IllegalArgumentException(
+                       "weights should be positive: w["+i+"]="+w[i]);
+       }
+       
+       for(int i=1; i<w.length; ++i) wsum[i]+=wsum[i-1];
+}
+
+
+// ======================= public methods ============================
+// ===================================================================
+
+
+/**
+* It initiates a random weighted permutation of the integeres from 0 to k-1.
+* It does not actually calculate the permutation.
+* The permutation can be read using method {@link #next}.
+* If the previous permutation was of the same length, it is more efficient.
+* The weights set at construction time work as follows.
+* The first sample is drawn according to the probability distribution
+* defined by the (normalized) weights.
+* After this the remaining k-1 elements and the associated k-1
+* (re-normalized) weights
+* define a new probability distribution, according to which the 2nd element
+* is drawn, and so on.
+* @param k the set is defined as 0,...,k-1
+*/
+public void reset(int k) {
+       
+       if( k<0 || k>w.length )
+               throw new IllegalArgumentException(
+                       "k should be non-negative and <= "+w.length);
+       
+       pointer = k;
+       sum = wsum[k-1];
+       
+       if( k != len )
+       {
+               // we need to initialize weights and buffer
+               for(int i=0; i<k; ++i)
+               {
+                       weights[i]=w[i];
+                       buffer[i]=i;
+               }
+               len=k;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+* The first sample is drawn according to the probability distribution
+* defined by the (normalized) weights.
+* After this the remaining k-1 elements and the associated k-1
+* (re-normalized) weights
+* define a new probability distribution, according to which the 2nd element
+* is drawn, and so on.
+* @see #reset
+*/
+public int next() {
+       
+       if( pointer < 1 ) throw new NoSuchElementException();
+       
+       double d = sum*r.nextDouble();
+       int i = pointer;
+       double tmp = weights[i-1];
+       while( tmp < d && i>1 ) tmp += weights[--i-1];
+       
+       // now i-1 is the selected element, we shift it to next position
+       int a = buffer[i-1];
+       double b = weights[i-1];
+       buffer[i-1] = buffer[pointer-1];
+       weights[i-1] = weights[pointer-1];
+       buffer[pointer-1] = a;
+       weights[pointer-1] = b;
+       sum -= b;
+       
+       return buffer[--pointer];
+}
+
+// -------------------------------------------------------------------
+
+public boolean hasNext() { return pointer > 0; }
+
+// -------------------------------------------------------------------
+
+/*
+public static void main( String pars[] ) throws Exception {
+       
+
+       int k = pars.length;
+       double w[] = new double[k];
+       for(int i=0; i<k; ++i) w[i] = Double.parseDouble(pars[i]);
+       
+       WeightedRandPerm rp = new WeightedRandPerm(new Random(),w);
+       rp.reset(k);
+       for(int i=0; i<1000; ++i)
+       {
+               if(i%2==0) rp.reset(k);
+               if(i%2==1) rp.reset(k-1);
+               while(rp.hasNext()) System.out.print(rp.next()+" ");
+               System.out.println();
+       }
+       
+       System.out.println();
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/vector/Getter.java b/contrib/psg/src/peersim/vector/Getter.java
new file mode 100644 (file)
index 0000000..a90e756
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import java.lang.reflect.*;
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Vectors can be written through this class. Typically {@link Control} classes
+ * use this to manipulate vectors.
+ * <p>
+ * The method to be used is specified at construction time.
+ * For backward compatibility, if no method is specified, the method
+ * <code>getValue</code> is used. In this way, protocols
+ * implementing the {@link SingleValue} interface can be manipulated using the
+ * old configuration syntax (i.e., without specifying the method).
+ * <p>
+ * Please refer to package {@link peersim.vector} for a detailed description of 
+ * the concept of protocol vector and the role of getters and setters. 
+ */
+public class Getter {
+
+// ============================ fields ===================================
+// =======================================================================
+
+private final String protocol;
+private final String methodn;
+private final String prefix;
+
+/** Identifier of the protocol that defines the vector */
+private int pid;
+
+/** Getter method name */
+private String methodName;
+
+/** Getter method */
+private Method method = null;
+
+/** Parameter type of getter method */
+private Class type;
+
+
+// ========================== initialization =============================
+// =======================================================================
+
+
+/**
+ * Constructs a Getter class based on the configuration. Note that the
+ * actual initialization is delayed until the first access to the class,
+ * so that if a class is not used, no unnecessary error messages and exceptions
+ * are generated.
+ * @param prefix the configuration prefix to use when reading the configuration
+ * @param protocol the configuration parameter name that contains
+ * the protocol we want to manipulate using a getter method.
+ * The parameter <code>prefix + "." + protocol</code> is read.
+ * @param methodn the configuration parameter name that contains the getter
+ * method name.
+ * The parameter <code>prefix + "." + methodn</code> is read, with the default
+ * value <code>getValue</code>.
+ */
+public Getter(String prefix, String protocol, String methodn) {
+
+       this.prefix=prefix;
+       this.protocol=protocol;
+       this.methodn=methodn;
+}
+
+// --------------------------------------------------------------------------
+
+/** Performs actual initialization */
+private void init() {
+
+       if( method!=null) return;
+
+       // Read configuration parameter
+       pid = Configuration.getPid(prefix + "." + protocol);
+       methodName = Configuration.getString(prefix+"."+methodn,"getValue");
+       // Search the method
+       Class clazz = Network.prototype.getProtocol(pid).getClass();
+       try {
+               method = GetterSetterFinder.getGetterMethod(clazz, methodName);
+       } catch (NoSuchMethodException e) {
+               throw new IllegalParameterException(prefix + "." +
+               methodn, e+"");
+       }
+       // Obtain the type of the field
+       type = GetterSetterFinder.getGetterType(method);
+}
+
+
+// =============================== methods =============================
+// =====================================================================
+
+/**
+* @return type of return value of getter method
+*/
+public Class getType() {
+
+       init();
+       return type;
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given value as a Number.
+* @param n The node to get the value on. The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public Number get(Node n) {
+       
+       init();
+
+       try 
+       {
+               Object ret =method.invoke(n.getProtocol(pid));
+               if (ret instanceof Boolean)
+                       return ((Boolean) ret) ? 1 : 0;
+               else
+                       return (Number) ret;
+       }
+       catch (Exception e)
+       {
+               throw new RuntimeException("While using getter "+methodName,e);
+       }
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given integer value.
+* @param n The node to get the value on. The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public long getLong(Node n) {
+       
+       init();
+
+       if(type==long.class || type==int.class)
+       {
+               try 
+               {
+                       return ((Number)
+                       method.invoke(n.getProtocol(pid))).longValue();
+               }
+               catch (Exception e)
+               {
+                       throw new RuntimeException(
+                       "While using getter "+methodName,e);
+               }
+       }       
+       else throw new RuntimeException("type has to be int or long");
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given real value.
+* @param n The node to get the value on. The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public double getDouble(Node n) {
+       
+       init();
+
+       if(type==double.class || type==float.class)
+       {
+               try
+               {
+                       return ((Number)
+                       method.invoke(n.getProtocol(pid))).doubleValue();
+               }
+               catch (Exception e)
+               {
+                       throw new RuntimeException(
+                       "While using getter "+methodName,e);
+               }
+       }
+       else throw new RuntimeException(
+                       "type has to be double or float");
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given value as a Number.
+* @param i The index of the node to get the value on in the network.
+* The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public Number get(int i) { return get(Network.get(i)); }
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given integer value.
+* @param i The index of the node to get the value on in the network.
+* The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public long getLong(int i) { return getLong(Network.get(i)); }
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given real value.
+* @param i The index of the node to get the value on in the network.
+* The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public double getDouble(int i) { return getDouble(Network.get(i)); }
+
+}
+
diff --git a/contrib/psg/src/peersim/vector/GetterSetterFinder.java b/contrib/psg/src/peersim/vector/GetterSetterFinder.java
new file mode 100644 (file)
index 0000000..48670be
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * This utility class can be used to obtain get/set methods from classes. In
+ * particular, it is used in the vector package to locate get/set methods for
+ * observing and modifying protocol fields.
+ * Please refer to package {@link peersim.vector} for a definition of
+ * getter and setter methods. 
+ */
+class GetterSetterFinder
+{
+
+//--------------------------------------------------------------------------
+
+/**
+ * Search a getter method in the specified class. It succeeds only of there
+ * is exactly one method with the given name that is a getter method.
+ * Please refer to package {@link peersim.vector} for a definition of
+ * getter methods. 
+ * 
+ * @param clazz
+ *          the class where to find get/set method
+ * @param methodName
+ *          the method to be searched
+ * @return the requested method
+ */
+public static Method getGetterMethod(Class clazz, String methodName)
+               throws NoSuchMethodException
+{
+       // Search methods
+       Method[] methods = clazz.getMethods();
+       ArrayList<Method> list = new ArrayList<Method>();
+       for (Method m: methods) {
+               if (m.getName().equals(methodName)) {
+                       list.add(m);
+               }
+       }
+       if (list.size() == 0) {
+               throw new NoSuchMethodException("No getter method for method "
+               + methodName + " in class " + clazz.getName());
+       } else if (list.size() > 1) {
+               throw new NoSuchMethodException("Multiple getter for method "
+               + methodName + " in class " + clazz.getName());
+       }
+       
+       // Found a single method with the right name; check if
+       // it is a gettter.
+       Method method = list.get(0);
+       Class[] pars = method.getParameterTypes();
+       if (pars.length > 0) {
+               throw new NoSuchMethodException(method.getName() + " of class "
+               + clazz.getName()
+               + " is not a valid getter method: "+
+               "its argument list is not empty");
+       }
+       
+       Class ret = method.getReturnType();
+       if (    !( ret==int.class || ret==long.class ||
+               ret==double.class || ret==float.class || ret==boolean.class)
+       ) {
+               throw new NoSuchMethodException(method.getName() + " of class "
+               + clazz.getName() + " is not a valid getter method: "+
+               "it should have a return type of int, long, short or double");
+       }
+       
+       return method;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Search a setter method in the specified class.
+ * It succeeds only of there
+ * is exactly one method with the given name that is a setter method.
+ * Please refer to package {@link peersim.vector} for a definition of
+ * setter methods. 
+ * @param clazz
+ *          the class where to find get/set method
+ * @param methodName
+ *          the method to be searched
+ * @return the requested method, if it fully conforms to the definition of
+ * the setter methods.
+ */
+public static Method getSetterMethod(Class clazz, String methodName)
+               throws NoSuchMethodException
+{
+       // Search methods
+       Method[] methods = clazz.getMethods();
+       ArrayList<Method> list = new ArrayList<Method>();
+       for (Method m: methods) {
+               if (m.getName().equals(methodName)) {
+                       list.add(m);
+               }
+       }
+       
+       if (list.size() == 0) {
+               throw new NoSuchMethodException("No setter method for method "
+               + methodName + " in class " + clazz.getName());
+       } else if (list.size() > 1) {
+               throw new NoSuchMethodException("Multiple setter for method "
+               + methodName + " in class " + clazz.getName());
+       }
+       
+       // Found a single method with the right name; check if
+       // it is a setter.
+       Method method = list.get(0);
+       Class[] pars = method.getParameterTypes();
+       if (    pars.length != 1 ||
+               !( pars[0]==int.class || pars[0]==long.class ||
+               pars[0]==double.class || pars[0]==float.class )
+       ) {
+               throw new NoSuchMethodException(method.getName() + " of class "
+               + clazz.getName()
+               + " is not a valid setter method: "+
+               "it should have exactly one argument of type "+
+               "int, long, short or double");
+       }
+       
+       Class ret = method.getReturnType();
+       if (!ret.equals(void.class)) {
+               throw new NoSuchMethodException(method.getName() + "  of class "
+               + clazz.getName() +
+               " is not a valid setter method; it returns a value");
+       }
+       
+       return method;
+}
+
+//--------------------------------------------------------------------------
+
+
+/**
+ * Returns the field type for the specified getter.
+ */
+public static Class getGetterType(Method m)
+{
+       return m.getReturnType();
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Returns the field type for the specified setter.
+ */
+public static Class getSetterType(Method m)
+{
+       Class[] pars = m.getParameterTypes();
+       return pars[0];
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/InitVectFromFile.java b/contrib/psg/src/peersim/vector/InitVectFromFile.java
new file mode 100644 (file)
index 0000000..1bfaa17
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import java.io.*;
+import java.util.*;
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Initializes a protocol vector from data read from a file.
+ * The file format is as follows:
+ * lines starting with # or lines that contain only
+ * whitespace are ignored.
+ * From the rest of the lines the first field separated by whitespace is
+ * read. Only the first field is read from each line, the rest of the line
+ * is ignored.
+ * The file can contain more values than necessary but
+ * enough values must be present.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class InitVectFromFile extends VectControl
+{
+
+// --------------------------------------------------------------------------
+// Parameter names
+// --------------------------------------------------------------------------
+
+/**
+ * The filename to load links from.
+ * @config
+ */
+private static final String PAR_FILE = "file";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** The file to be read */
+private final String file;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public InitVectFromFile(String prefix)
+{
+       super(prefix);
+       file = Configuration.getString(prefix + "." + PAR_FILE);
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Initializes values from a file.
+ * The file format is as follows:
+ * lines starting with # or lines that contain only
+ * whitespace are ignored.
+ * From the rest of the lines the first field separated by whitespace is
+ * read. Only the first field is read from each line, the rest of the line
+ * is ignored.
+ * The file can contain more values than necessary but
+ * enough values must be present.
+ * @throws RuntimeException if the file cannot be read or contains too few
+ * values
+ * @return always false
+ */
+public boolean execute() {
+
+       int i = 0;
+
+try {
+       FileReader fr = new FileReader(file);
+       LineNumberReader lnr = new LineNumberReader(fr);
+       String line;
+       while ((line = lnr.readLine()) != null && i < Network.size()) {
+               if (line.startsWith("#"))
+                       continue;
+               StringTokenizer st = new StringTokenizer(line);
+               if (!st.hasMoreTokens())
+                       continue;
+               if( setter.isInteger() )
+                       setter.set(i,Long.parseLong(st.nextToken()));
+               else    setter.set(i,Double.parseDouble(st.nextToken()));
+               i++;
+       }
+       lnr.close();
+}
+catch(IOException e)
+{
+       throw new RuntimeException("Unable to read file: " + e);
+}
+       
+       if (i < Network.size())
+               throw new RuntimeException(
+               "Too few values in file '" + file + "' (only "
+               + i + "); we need " + Network.size() + ".");
+       
+       return false;
+}
+
+// --------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/LinearDistribution.java b/contrib/psg/src/peersim/vector/LinearDistribution.java
new file mode 100644 (file)
index 0000000..e7cc19e
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Initializes a protocol vector with values in the range [{@value #PAR_MIN}, 
+ * {@value #PAR_MAX}] (inclusive both ends), linearly increasing.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class LinearDistribution extends VectControl
+{
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * Upper end of the interval..
+ * @config
+ */
+private static final String PAR_MAX = "max";
+
+/**
+ * Lower end of the interval. Defaults to -{@value #PAR_MAX}.
+ * @config
+ */
+private static final String PAR_MIN = "min";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Minimum value */
+private final Number min;
+
+/** Maximum value */
+private final Number max;
+
+/** Step value */
+private final double step;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public LinearDistribution(String prefix)
+{
+       super(prefix);
+       
+       // Read parameters based on type
+       if (setter.isInteger()) {
+               max=Long.valueOf(Configuration.getLong(prefix + "." + PAR_MAX));
+               min=Long.valueOf(Configuration.getLong(prefix + "." + PAR_MIN, 
+                               -max.longValue()));
+               step= (max.longValue()-min.longValue())/
+                       ((double)(Network.size()-1));
+       } else { // we know it's double or float
+               max = new Double(Configuration.getDouble(prefix+"."+PAR_MAX));
+               min = new Double(Configuration.getDouble(prefix+"."+PAR_MIN, 
+                               -max.doubleValue()));
+               step= (max.doubleValue()-min.doubleValue())/(Network.size()-1);
+       }
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Initializes a protocol vector with values in the range [{@value #PAR_MIN}, 
+ * {@value #PAR_MAX}] (inclusive both ends), linearly increasing.
+ * @return always false
+ */
+public boolean execute() {
+       
+       if ( setter.isInteger() )
+       {
+               for(int i=0; i<Network.size(); ++i)
+               {
+                       // we avoid the entire expression being cast to double
+                       setter.set(i,Math.round(i*step)+min.longValue());
+               }
+       }
+       else
+       {
+               for(int i=0; i<Network.size(); ++i)
+               {
+                       setter.set(i,i*step+min.doubleValue());
+               }
+       }
+
+       return false;
+}
+
+
+}
+
+
diff --git a/contrib/psg/src/peersim/vector/Normalizer.java b/contrib/psg/src/peersim/vector/Normalizer.java
new file mode 100644 (file)
index 0000000..5aa4383
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Normalizes the values of a protocol vector.
+ * The normalization is based on the L1 norm, that is, the sum of the
+ * absolute values of the vector elements. Parameter {@value #PAR_L1} defines
+ * the L1 norm that the vector will have after normalization.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class Normalizer extends VectControl
+{
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/**
+ * The L1 norm (sum of absolute values) to normalize to. After the operation the
+ * L1 norm will be the value given here. Defaults to 1.
+ * @config
+ */
+private static final String PAR_L1 = "l1";
+
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** L1 norm */
+private final double l1;
+
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public Normalizer(String prefix)
+{
+       super(prefix);
+       l1 = Configuration.getDouble(prefix + "." + PAR_L1, 1);
+       
+       if( setter.isInteger() ) 
+               throw new IllegalParameterException(prefix + "." + PAR_METHOD,
+                       "setter value must be floating point, instead of "+
+                       setter.getType());
+                       
+       if( setter.getType() !=  getter.getType() )
+               throw new IllegalParameterException(prefix + "." + PAR_GETTER,
+               "getter and setter must have the same numeric type, "+
+               "but we have "+setter.getType()+" and "+getter.getType());
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Makes the sum of the absolute values (L1 norm) equal to the value
+ * given in the configuration parameter {@value #PAR_L1}. If the value is
+ * negative, the L1 norm will be the absolute value and the vector elements
+ * change sign.
+ * @return always false
+ */
+public boolean execute() {
+       
+       double sum = 0.0;
+       for (int i = 0; i < Network.size(); ++i)
+       {
+               sum += getter.getDouble(i);
+       }
+       if (sum == 0.0)
+       {
+               throw new
+               RuntimeException("Attempted to normalize all zero vector.");
+       }
+       double factor = l1 / sum;
+       for (int i = 0; i < Network.size(); ++i)
+       {
+               double val = getter.getDouble(i)*factor;
+               setter.set(i,val);
+       }
+       return false;
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/PeakDistribution.java b/contrib/psg/src/peersim/vector/PeakDistribution.java
new file mode 100644 (file)
index 0000000..c9f1309
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import peersim.config.*;
+import peersim.core.*;
+
+
+/**
+ * Initializes the values so that {@value #PAR_PEAKS} nodes have value
+ * {@value #PAR_VALUE}/{@value #PAR_PEAKS}, the rest {@value #PAR_LVALUE}
+ * (zero by default).
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class PeakDistribution extends VectControl
+{
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/** 
+ * The sum of values in the system, to be equally distributed between peak 
+ * nodes.
+ * @config
+ */
+private static final String PAR_VALUE = "value";
+
+/** 
+ * The value for the nodes that are not peaks. This parameter is optional,
+ * by default, the nodes that are
+ * not peaks are set to zero. This value overrides that behavior.
+ * @config
+ */
+private static final String PAR_LVALUE = "background";
+
+/** 
+ * The number of peaks in the system. If this value is greater than or equal to
+ * 1, it is interpreted as the actual number of peaks. If it is included in 
+ * the range [0, 1] it is interpreted as a percentage with respect to the
+ * current network size. Defaults to 1. 
+ * @config
+ */
+private static final String PAR_PEAKS = "peaks";
+
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Total load */
+private final Number lvalue;
+
+/** Total load */
+private final Number value;
+
+/** Number of peaks */
+private final double peaks;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public PeakDistribution(String prefix)
+{
+       super(prefix);
+       
+       peaks = Configuration.getDouble(prefix+"."+PAR_PEAKS, 1);
+       
+       if( setter.isInteger() )
+       {
+               value=Long.valueOf(Configuration.getLong(prefix+"."+PAR_VALUE));
+               lvalue=Long.valueOf(Configuration.getLong(prefix+"."+PAR_LVALUE,0));
+       }
+       else
+       {
+               value = new Double(Configuration.getDouble(prefix + "." +
+               PAR_VALUE));
+               lvalue = new Double(Configuration.getDouble(prefix + "." +
+               PAR_LVALUE,0));
+       }
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Initializes the values so that {@value #PAR_PEAKS} nodes have value
+ * {@value #PAR_VALUE}/{@value #PAR_PEAKS}, the rest zero.
+ * @return always false
+ */
+public boolean execute()
+{
+       int pn = (peaks < 1 ? (int) (peaks*Network.size()) : (int) peaks);
+       
+       if( setter.isInteger() )
+       {
+               long v = value.longValue()/pn;
+               long lv = lvalue.longValue();
+               for (int i=0; i < pn; i++) setter.set(i, v);
+               for (int i=pn; i < Network.size(); i++) setter.set(i,lv);
+       }
+       else
+       {
+               double v = value.doubleValue()/pn;
+               double lv = lvalue.doubleValue();
+               for (int i=0; i < pn; i++) setter.set(i, v);
+               for (int i=pn; i < Network.size(); i++) setter.set(i,lv);
+       }
+
+       return false;
+}
+
+// --------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/Setter.java b/contrib/psg/src/peersim/vector/Setter.java
new file mode 100644 (file)
index 0000000..cfcf54c
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import java.lang.reflect.*;
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Vectors can be written through this class. Typically {@link Control} classes
+ * use this to manipulate vectors.
+ * <p>
+ * The method to be used is specified at construction time.
+ * For backward compatibility, if no method is specified, the method
+ * <code>setValue</code> is used. In this way, protocols
+ * implementing the {@link SingleValue} interface can be manipulated using the
+ * old configuration syntax (i.e., without specifying the method).
+ * <p>
+ * Please refer to package {@link peersim.vector} for a detailed description of 
+ * the concept of protocol vector and the role of getters and setters. 
+ */
+public class Setter {
+
+// ============================ fields ===================================
+// =======================================================================
+
+private final String protocol;
+private final String methodn;
+private final String prefix;
+
+/** Identifier of the protocol that defines the vector */
+private int pid;
+
+/** Setter method name */
+private String methodName;
+
+/** Setter method */
+private Method method=null;
+
+/** Parameter type of setter method */
+private Class type;
+
+
+// ========================== initialization =============================
+// =======================================================================
+
+
+/**
+ * Constructs a Setter class based on the configuration.
+ * Note that the
+ * actual initialization is delayed until the first access to the class,
+ * so that if a class is not used, no unnecessary error messages and exceptions
+ * are generated.
+ * @param prefix the configuration prefix to use when reading the configuration
+ * @param protocol the configuration parameter name that contains
+ * the protocol we want to manipulate using a setter method.
+ * The parameter <code>prefix + "." + protocol</code> is read.
+ * @param methodn the configuration parameter name that contains the setter
+ * method name.
+ * The parameter <code>prefix + "." + methodn</code> is read, with the default
+ * value <code>setValue</code>.
+ */
+public Setter(String prefix, String protocol, String methodn) {
+       
+       this.prefix=prefix;
+       this.protocol=protocol;
+       this.methodn=methodn;
+}
+
+// --------------------------------------------------------------------------
+
+private void init() {
+
+       if( method!=null) return;
+
+       // Read configuration parameter
+       pid = Configuration.getPid(prefix + "." + protocol);
+       methodName = Configuration.getString(prefix+"."+methodn,"setValue");
+       // Search the method
+       Class clazz = Network.prototype.getProtocol(pid).getClass();
+       try {
+               method = GetterSetterFinder.getSetterMethod(clazz, methodName);
+       } catch (NoSuchMethodException e) {
+               throw new IllegalParameterException(prefix + "." +
+               methodn, e+"");
+       }
+       // Obtain the type of the field
+       type = GetterSetterFinder.getSetterType(method);
+}
+
+
+// =============================== methods =============================
+// =====================================================================
+
+
+/**
+* @return type of parameter of setter method
+*/
+public Class getType() {
+
+       init();
+       return type;
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* @return true if the setter type is long or int
+*/
+public boolean isInteger() {
+
+       init();
+       return type==long.class || type==int.class;
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Sets the given integer value.
+* @param n The node to set the value on. The protocol is defined
+* by {@link #pid}.
+* @param val the value to set.
+*/
+public void set(Node n, long val) {
+       
+       init();
+       
+       try 
+       {
+               if(type==long.class)
+               {
+                       method.invoke(n.getProtocol(pid),val);
+                       return;
+               }
+               if(type==int.class)
+               {
+                       method.invoke(n.getProtocol(pid),(int)val);
+                       return;
+               }
+       }
+       catch (Exception e)
+       {
+               throw new RuntimeException("While using setter "+methodName,e);
+               
+       }
+       
+       throw new RuntimeException("type has to be int or long");
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Sets the given real value.
+* @param n The node to set the value on. The protocol is defined
+* by {@link #pid}.
+* @param val the value to set.
+*/
+public void set(Node n, double val) {
+       
+       init();
+       
+       try
+       {
+               if(type==double.class)
+               {
+                       method.invoke(n.getProtocol(pid),val);
+                       return;
+               }
+               if(type==float.class)
+               {
+                       method.invoke(n.getProtocol(pid),(float)val);
+                       return;
+               }
+       }
+       catch (Exception e)
+       {
+               throw new RuntimeException("While using setter "+methodName,e);
+       }
+       
+       throw new RuntimeException("type has to be double or float");
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Sets the given integer value.
+* @param i The index of the node to set the value on in the network.
+* The protocol is defined
+* by {@link #pid}.
+* @param val the value to set.
+*/
+public void set(int i, long val) { set(Network.get(i),val); }
+
+// --------------------------------------------------------------------------
+
+/**
+* Sets the given real value.
+* @param i The index of the node to set the value on in the network.
+* The protocol is defined
+* by {@link #pid}.
+* @param val the value to set.
+*/
+public void set(int i, double val) { set(Network.get(i),val); }
+
+}
+
diff --git a/contrib/psg/src/peersim/vector/SingleValue.java b/contrib/psg/src/peersim/vector/SingleValue.java
new file mode 100644 (file)
index 0000000..8d3dd9e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+/**
+* The implementor class has a single parameter. This interface
+* provides access to that parameter.
+*/
+public interface SingleValue {
+
+/**
+ * Returns the value of the parameter hold by the implementor
+ * of this interface. 
+ */
+public double getValue();
+
+/**
+ * Modifies the value of the parameter hold by the implementor
+ * of this interface. 
+ */
+public void setValue(double value);
+
+}
+
diff --git a/contrib/psg/src/peersim/vector/SingleValueComparator.java b/contrib/psg/src/peersim/vector/SingleValueComparator.java
new file mode 100644 (file)
index 0000000..0fa324e
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import peersim.core.*;
+import java.util.*;
+
+/**
+ * This comparator class compares two node objects based on the value 
+ * maintained by one of its protocols. The protocol must implement the
+ * {@link SingleValue} interface; its identifier has to be specified when a
+ * new comparator is built.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.4 $
+ */
+public class SingleValueComparator implements Comparator 
+{
+
+/** Protocol to be be compared */
+private int pid;
+
+/**
+ * Builds a new comparator that compares the double values maintained
+ * by protocol identified by <code>pid</code>.
+ */
+public SingleValueComparator(int pid) { this.pid = pid; }
+
+/**
+ * Compares the values of two protocols. The parameters must have dynamic type
+ * {@link Node}. The protocol {@link #pid} is accessed on both nodes. These
+ * protocols have to implement the {@link SingleValue} interface. The values
+ * held by these protocol instances are then compared.
+ */
+public int compare(Object o1, Object o2)
+{
+       SingleValue s1 = (SingleValue) ((Node) o1).getProtocol(pid);
+       SingleValue s2 = (SingleValue) ((Node) o2).getProtocol(pid);
+       return (int) (s1.getValue() - s2.getValue());
+}
+       
+}
diff --git a/contrib/psg/src/peersim/vector/SingleValueHolder.java b/contrib/psg/src/peersim/vector/SingleValueHolder.java
new file mode 100644 (file)
index 0000000..450086d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import peersim.core.*;
+
+/**
+ * The task of this protocol is to store a single double value and make it
+ * available through the {@link SingleValue} interface.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.6 $
+ */
+public class SingleValueHolder 
+implements SingleValue, Protocol
+{
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+       
+/** Value held by this protocol */
+protected double value;
+       
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Does nothing.
+ */
+public SingleValueHolder(String prefix)
+{
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Clones the value holder.
+ */
+public Object clone()
+{
+       SingleValueHolder svh=null;
+       try { svh=(SingleValueHolder)super.clone(); }
+       catch( CloneNotSupportedException e ) {} // never happens
+       return svh;
+}
+
+//--------------------------------------------------------------------------
+//methods
+//--------------------------------------------------------------------------
+
+/**
+ * @inheritDoc
+ */
+public double getValue()
+{
+       return value;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * @inheritDoc
+ */
+public void setValue(double value)
+{
+       this.value = value;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Returns the value as a string.
+ */
+public String toString() { return ""+value; }
+
+}
diff --git a/contrib/psg/src/peersim/vector/SingleValueObserver.java b/contrib/psg/src/peersim/vector/SingleValueObserver.java
new file mode 100644 (file)
index 0000000..262d2e0
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.vector;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+* Print statistics over a vector. The vector is defined by a protocol,
+* specified by {@value #PAR_PROT}, that has to  implement
+* {@link SingleValue}.
+* Statistics printed are: min, max, number of samples, average, variance,
+* number of minimal instances, number of maximal instances (using
+* {@link IncrementalStats#toString}).
+* @see IncrementalStats
+*/
+public class SingleValueObserver implements Control {
+
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/** 
+ *  The parameter used to determine the accuracy
+ *  (standard deviation) before stopping the simulation. If not 
+ *  defined, a negative value is used which makes sure the observer 
+ *  does not stop the simulation.
+ * @see #execute
+ *  @config
+ */
+private static final String PAR_ACCURACY = "accuracy";
+
+/**
+ * The protocol to operate on.
+ * @config
+ */
+private static final String PAR_PROT = "protocol";
+
+
+//--------------------------------------------------------------------------
+// Fields
+//--------------------------------------------------------------------------
+
+/** The name of this observer in the configuration */
+private final String name;
+
+/** Accuracy for standard deviation used to stop the simulation */
+private final double accuracy;
+
+/** Protocol identifier */
+private final int pid;
+
+
+//--------------------------------------------------------------------------
+// Constructor
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public SingleValueObserver(String name)
+{
+       this.name = name;
+       accuracy = Configuration.getDouble(name + "." + PAR_ACCURACY, -1);
+       pid = Configuration.getPid(name + "." + PAR_PROT);
+}
+
+
+//--------------------------------------------------------------------------
+// Methods
+//--------------------------------------------------------------------------
+
+/**
+* Print statistics over a vector. The vector is defined by a protocol,
+* specified by {@value #PAR_PROT}, that has to  implement
+* {@link SingleValue}.
+* Statistics printed are: min, max, number of samples, average, variance,
+* number of minimal instances, number of maximal instances (using 
+* {@link IncrementalStats#toString}).
+* @return true if the standard deviation is below the value of
+ * {@value #PAR_ACCURACY}, and the time of the simulation is larger then zero
+ * (i.e. it has started).
+ */
+public boolean execute()
+{
+       IncrementalStats stats = new IncrementalStats();
+       
+       /* Compute max, min, average */
+       for (int i = 0; i < Network.size(); i++)
+       {
+               SingleValue v = (SingleValue)Network.get(i).getProtocol(pid);
+               stats.add( v.getValue() );
+       }
+
+       /* Printing statistics */
+       System.out.println(name+": "+stats);
+
+       /* Terminate if accuracy target is reached */
+       return (stats.getStD()<=accuracy && CommonState.getTime()>0);
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/TestVectors.java b/contrib/psg/src/peersim/vector/TestVectors.java
new file mode 100644 (file)
index 0000000..f6920cb
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+
+/**
+ * Do testing the vector package.
+ */
+public class TestVectors extends SingleValueHolder
+{
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+       
+/** Value held by this protocol */
+protected float fvalue;
+
+/** Value held by this protocol */
+protected int ivalue;
+
+/** Value held by this protocol */
+protected long lvalue;
+       
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Builds a new (not initialized) value holder.
+ * Calls super constructor.
+ */
+public TestVectors(String prefix) { super(prefix); }
+
+//--------------------------------------------------------------------------
+//methods
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public int getIValue() { return ivalue; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public void setIValue(int value) { ivalue = value; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public float getFValue() { return fvalue; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public void setFValue(float value) { fvalue = value; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public long getLValue() { return lvalue; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public void setLValue(long value) { lvalue = value; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * Returns the value as a string.
+ */
+public String toString() { return value+" "+fvalue+" "+ivalue+" "+lvalue; }
+
+}
+
diff --git a/contrib/psg/src/peersim/vector/UniformDistribution.java b/contrib/psg/src/peersim/vector/UniformDistribution.java
new file mode 100644 (file)
index 0000000..bd30fb1
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.dynamics.*;
+
+/**
+ * Initializes the values drawing uniform random samples from the range
+ * [{@value #PAR_MIN}, {@value #PAR_MAX}[.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class UniformDistribution extends VectControl implements NodeInitializer
+{
+
+//--------------------------------------------------------------------------
+//Parameter names
+//--------------------------------------------------------------------------
+
+/**
+ * The upper bound of the uniform random variable, exclusive.
+ * @config
+ */
+private static final String PAR_MAX = "max";
+
+/**
+ * The lower bound of the uniform
+ * random variable, inclusive. Defaults to -{@value #PAR_MAX}.
+ * @config
+ */
+private static final String PAR_MIN = "min";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Minimum value */
+private final Number min;
+
+/** Maximum value */
+private final Number max;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public UniformDistribution(String prefix)
+{
+       super(prefix);
+       
+       // Read parameters based on type
+       if (setter.isInteger()) {
+               max=Long.valueOf(Configuration.getLong(prefix + "." + PAR_MAX));
+               min=Long.valueOf(Configuration.getLong(prefix + "." + PAR_MIN, 
+                               -max.longValue()));
+       } else { // we know it's double or float
+               max = new Double(Configuration.getDouble(prefix+"."+PAR_MAX));
+               min = new Double(Configuration.getDouble(prefix+"."+PAR_MIN, 
+                               -max.doubleValue()));
+       }
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Initializes the values drawing uniform random samples from the range
+ * [{@value #PAR_MIN}, {@value #PAR_MAX}[.
+ * @return always false
+ */
+public boolean execute() {
+
+       if(setter.isInteger())
+       {
+               long d = max.longValue() - min.longValue();
+               for (int i = 0; i < Network.size(); ++i)
+               {
+                       setter.set(i,CommonState.r.nextLong(d)+min.longValue());
+               }
+       }
+       else
+       {
+               double d = max.doubleValue() - min.doubleValue();
+               for (int i = 0; i < Network.size(); ++i)
+               {
+                       setter.set(i,CommonState.r.nextDouble()*d+
+                       min.doubleValue());
+               }
+       }
+
+       return false;
+}
+
+// --------------------------------------------------------------------------
+
+/**
+ * Initializes the value drawing a uniform random sample from the range
+ * [{@value #PAR_MIN}, {@value #PAR_MAX}[.
+ * @param n the node to initialize
+ */
+public void initialize(Node n) {
+
+       if( setter.isInteger() )
+       {
+               long d = max.longValue() - min.longValue();
+               setter.set(n,CommonState.r.nextLong(d) + min.longValue());
+       }
+       else
+       {
+               double d = max.doubleValue() - min.doubleValue();
+               setter.set(n,CommonState.r.nextDouble()*d);
+       }
+}
+
+// --------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/ValueDumper.java b/contrib/psg/src/peersim/vector/ValueDumper.java
new file mode 100644 (file)
index 0000000..ce6746e
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import java.io.*;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * Dump the content of a vector in a file. Each line
+ * represent a single node.
+ * Values are dumped to a file whose name is obtained from a
+ * configurable prefix (set by {@value #PAR_BASENAME}), a number that is
+ * increased before each dump by one, and the extension ".vec".
+ * <p>
+ * This observer class can observe any protocol field containing a 
+ * primitive value, provided that the field is associated with a getter method 
+ * that reads it.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class ValueDumper extends VectControl {
+
+
+// --------------------------------------------------------------------------
+// Parameter names
+// --------------------------------------------------------------------------
+
+/**
+ * This is the base name of the file where the values are saved. The full name
+ * will be baseName+cycleid+".vec".
+ * @config
+ */
+private static final String PAR_BASENAME = "outf";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Prefix name of this observer */
+private final String prefix;
+
+/** Base name of the file to be written */
+private final String baseName;
+
+private final FileNameGenerator fng;
+
+// --------------------------------------------------------------------------
+// Constructor
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public ValueDumper(String prefix) {
+
+       super(prefix);
+       this.prefix = prefix;
+       baseName = Configuration.getString(prefix + "." + PAR_BASENAME, null);
+       if(baseName!=null) fng = new FileNameGenerator(baseName,".vec");
+       else fng = null;
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Dump the content of a vector in a file. Each line
+ * represent a single node.
+ * Values are dumped to a file whose name is obtained from a
+ * configurable prefix (set by {@value #PAR_BASENAME}), a number that is
+ * increased before each dump by one, and the extension ".vec".
+ * @return always false
+ * @throws RuntimeException if there is an I/O problem
+ */
+public boolean execute() {
+try
+{
+       System.out.print(prefix + ": ");
+       
+       // initialize output streams
+       if (baseName != null)
+       {
+               String filename = fng.nextCounterName();
+               System.out.println("writing "+filename);
+               PrintStream pstr =
+                       new PrintStream(new FileOutputStream(filename));
+               for (int i = 0; i < Network.size(); ++i)
+               {
+                       pstr.println(getter.get(i));
+               }
+               pstr.close();
+       }
+       else
+       {
+               System.out.println();
+               for (int i = 0; i < Network.size(); ++i)
+               {
+                       System.out.println(getter.get(i));
+               }
+       }
+}
+catch (IOException e)
+{
+       throw new RuntimeException(prefix + ": Unable to write to file: " + e);
+}
+
+       return false;
+}
+
+// ---------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/VectAngle.java b/contrib/psg/src/peersim/vector/VectAngle.java
new file mode 100644 (file)
index 0000000..629a06e
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import peersim.core.*;
+
+/**
+ * Observes the cosine angle between two vectors. The number which is output is
+ * the inner product divided by the product of the length of the vectors.
+ * All values are converted to double before processing.
+ * <p>
+ * This observer class can observe any protocol field containing a 
+ * primitive value, provided that the field is associated with a getter method 
+ * that reads it.
+ * The methods to be used are specified through parameter {@value #PAR_METHOD1}
+ * and {@value #PAR_METHOD2}.
+ * <p>
+ * Please refer to package {@link peersim.vector} for a detailed description of 
+ * this mechanism. 
+ */
+public class VectAngle implements Control
+{
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/**
+ * The first protocol to be observed.
+ * @config
+ */
+private static final String PAR_PROT1 = "protocol1";
+
+/**
+ * The second protocol to be observed.
+ * @config
+ */
+private static final String PAR_PROT2 = "protocol2";
+
+/**
+ * The getter method used to obtain the values of the first protocol. 
+ * Defaults to <code>getValue</code> (for backward compatibility with previous 
+ * implementation of this class, that were based on the 
+ * {@link SingleValue} interface).
+ * Refer to the {@linkplain peersim.vector vector package description} for more 
+ * information about getters and setters.
+ * @config
+ */
+private static final String PAR_METHOD1 = "getter1";
+
+/**
+ * The getter method used to obtain the values of the second protocol. 
+ * Defaults to <code>getValue</code> (for backward compatibility with previous 
+ * implementation of this class, that were based on the 
+ * {@link SingleValue} interface).
+ * Refer to the {@linkplain peersim.vector vector package description} for more 
+ * information about getters and setters.
+ * @config
+ */
+private static final String PAR_METHOD2 = "getter2";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** The prefix for this observer*/
+private final String name;
+
+private final Getter getter1;
+
+private final Getter getter2;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public VectAngle(String prefix)
+{
+       name = prefix;
+       getter1 = new Getter(prefix,PAR_PROT1,PAR_METHOD1);
+       getter2 = new Getter(prefix,PAR_PROT2,PAR_METHOD2);
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Observes the cosine angle between two vectors. The printed values
+ * are: cosine, Eucledian norm of vect 1, Eucledian norm of vector 2,
+ * angle in radians.
+* @return always false
+*/
+public boolean execute() {
+
+       double sqrsum1 = 0, sqrsum2 = 0, prod = 0;
+       for (int i = 0; i < Network.size(); ++i)
+       {
+               double v1= getter1.get(i).doubleValue();
+               double v2= getter2.get(i).doubleValue();
+               sqrsum1 += v1 * v1;
+               sqrsum2 += v2 * v2;
+               prod += v2 * v1;
+       }
+       
+       double cos = prod / Math.sqrt(sqrsum1) / Math.sqrt(sqrsum2);
+       
+       // deal with numeric errors
+       if( cos > 1 ) cos=1;
+       if( cos < -1 ) cos = -1;
+       
+       System.out.println(name+": " + cos + " "
+                       + Math.sqrt(sqrsum1) + " " + Math.sqrt(sqrsum2) + " "
+                       + Math.acos(cos));
+       return false;
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/VectControl.java b/contrib/psg/src/peersim/vector/VectControl.java
new file mode 100644 (file)
index 0000000..174b962
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import peersim.core.*;
+
+/**
+ * Serves as an abstract superclass for {@link Control}s that deal
+ * with vectors.
+ * It reads a {@link Setter} to be used by extending classes.
+ */
+public abstract class VectControl implements Control {
+
+
+// --------------------------------------------------------------------------
+// Parameter names
+// --------------------------------------------------------------------------
+
+/**
+ * The protocol to operate on.
+ * @config
+ */
+protected static final String PAR_PROT = "protocol";
+
+/**
+ * The setter method used to set values in the protocol instances. Defaults to
+ * <code>setValue</code>
+ * (for backward compatibility with previous implementation of this
+ * class, that were based on the {@link SingleValue} interface). Refer to the
+ * {@linkplain peersim.vector vector package description} for more
+ * information about getters and setters.
+ * @config
+ */
+protected static final String PAR_METHOD = "setter";
+
+/**
+ * The getter method used to obtain the protocol values. 
+ * Defaults to <code>getValue</code>
+ * (for backward compatibility with previous 
+ * implementation of this class, that were based on the 
+ * {@link SingleValue} interface).
+ * Refer to the {@linkplain peersim.vector vector package description} for more 
+ * information about getters and setters.
+ * @config
+ */
+protected static final String PAR_GETTER = "getter";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** The setter to be used to write a vector. */
+protected final Setter setter;
+
+/** The getter to be used to read a vector. */
+protected final Getter getter;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+protected VectControl(String prefix)
+{
+       setter = new Setter(prefix,PAR_PROT,PAR_METHOD);
+       getter = new Getter(prefix,PAR_PROT,PAR_GETTER);
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/vector/VectCopy.java b/contrib/psg/src/peersim/vector/VectCopy.java
new file mode 100644 (file)
index 0000000..6d13091
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import peersim.core.*;
+import peersim.dynamics.*;
+
+/**
+ * Sets values in a protocol vector by copying the values of another 
+ * protocol vector.
+ * The source is defined by {@value #PAR_SOURCE},
+ * and getter method {@value peersim.vector.VectControl#PAR_GETTER}.
+ * <p>
+ * This dynamics class can copy any primitive field in the source
+ * protocol to any primitive field in the destination protocol,
+ * provided that the former field is associated with a getter method,
+ * while the latter is associated with a setter method.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class VectCopy extends VectControl implements  NodeInitializer {
+
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The identifier of the protocol to be copied.
+ * The vector values are copied from this vector.
+ * @config
+ */
+private static final String PAR_SOURCE = "source";
+
+
+// --------------------------------------------------------------------------
+// Variables
+// --------------------------------------------------------------------------
+
+/** Source getter */
+private final Getter source;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public VectCopy(String prefix)
+{
+       super(prefix);
+       source = new Getter(prefix,PAR_SOURCE,PAR_GETTER);
+}
+
+//--------------------------------------------------------------------------
+//Method
+//--------------------------------------------------------------------------
+
+/**
+ * Sets values in a protocol vector by copying the values of another 
+ * protocol vector. The source is defined by {@value #PAR_SOURCE},
+ * and getter method {@value peersim.vector.VectControl#PAR_GETTER}.
+ * @return always false
+ */
+public boolean execute() {
+
+       int size = Network.size();
+       for (int i = 0; i < size; i++) {
+               Number ret = source.get(i);
+               if(setter.isInteger()) setter.set(i,ret.longValue());
+               else setter.set(i,ret.doubleValue());
+       }
+
+       return false;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Sets the value by copying the value of another 
+ * protocol. The source is  defined by {@value #PAR_SOURCE},
+ * and getter method {@value peersim.vector.VectControl#PAR_GETTER}.
+ * @param n the node to initialize
+ */
+public void initialize(Node n) {
+
+       Number ret = source.get(n);
+       if(setter.isInteger()) setter.set(n,ret.longValue());
+       else setter.set(n,ret.doubleValue());
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/VectorComparator.java b/contrib/psg/src/peersim/vector/VectorComparator.java
new file mode 100644 (file)
index 0000000..97f269e
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.vector;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import peersim.core.*;
+
+/**
+ * This class provides a generic implementation of the
+ * <code>java.lang.Comparator<code> interface specialized
+ * for {@link Node} objects. Nodes are compared based
+ * on one of their protocols, on which a configurable
+ * method is invoked. Both the protocol id and the
+ * method are specified in the constructor.
+ * <br>
+ * This comparator can be used, for example, to sort
+ * an array of nodes based on method <code>getValue</code>
+ * associated to the protocol <code>pid</code>:
+ * <PRE>
+ * Comparator c = new VectorComparator(pid, "getValue");
+ * Array.sort(Node[] array, c);
+ * </PRE>
+ * Note that differently from other classes in this package,
+ * VectorComparator is declared programmatically in the code
+ * and not in the configuration file. It is included in this
+ * package because it shares the same philosophy of the other
+ * classes.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.1 $
+ */
+public class VectorComparator implements Comparator
+{
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/** Protocol identifier of the protocol to be observed */
+private final int pid;
+
+/** The getter to be used to obtain comparable values */
+private final Method method;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+public VectorComparator(int pid, String methodName)
+{
+       this.pid = pid;
+       Node n = Network.prototype;
+       if (n == null) {
+               throw new IllegalStateException("No prototype node can be used to search methods");
+       }
+       Object p = n.getProtocol(pid);
+       Class c = p.getClass();
+       try {
+               method = GetterSetterFinder.getGetterMethod(c, methodName);
+       } catch (NoSuchMethodException e) {
+               throw new IllegalArgumentException(e.getMessage());
+       }
+}
+
+
+public int compare(Object o1, Object o2)
+{
+       try {
+       Comparable c1 = (Comparable) method.invoke(((Node) o1).getProtocol(pid));
+       Comparable c2 = (Comparable) method.invoke(((Node) o2).getProtocol(pid));
+       return c1.compareTo(c2);
+       } catch (InvocationTargetException e) {
+               throw new RuntimeException(e.getCause().getMessage());
+       } catch (IllegalAccessException e) {
+               throw new RuntimeException(e.getCause().getMessage());
+       }
+}
+
+}
diff --git a/contrib/psg/src/peersim/vector/VectorObserver.java b/contrib/psg/src/peersim/vector/VectorObserver.java
new file mode 100644 (file)
index 0000000..b971fc2
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+               
+package peersim.vector;
+
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * This class computes and reports statistics information about a vector.
+ * Provided statistics include average, max, min, variance,
+ * etc. Values are printed according to the string format of {@link 
+ * IncrementalStats#toString}.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class VectorObserver extends VectControl {
+
+
+/** The name of this observer in the configuration */
+private final String prefix;
+
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public VectorObserver(String prefix) {
+
+       super(prefix);
+       this.prefix = prefix;
+}
+
+//--------------------------------------------------------------------------
+// Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Prints statistics information about a vector.
+ * Provided statistics include average, max, min, variance,
+ * etc. Values are printed according to the string format of {@link 
+ * IncrementalStats#toString}.
+ * @return always false
+ */
+public boolean execute() {
+
+       IncrementalStats stats = new IncrementalStats();
+
+       for (int j = 0; j < Network.size(); j++)
+       {
+               Number v = getter.get(j);
+               stats.add( v.doubleValue() );
+       }
+       
+       System.out.println(prefix+": "+stats);  
+
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/psgsim/NodeHost.java b/contrib/psg/src/psgsim/NodeHost.java
new file mode 100644 (file)
index 0000000..1dce76f
--- /dev/null
@@ -0,0 +1,74 @@
+package psgsim;
+
+import org.simgrid.msg.Host;
+import peersim.core.Network;
+import peersim.core.Node;
+
+import java.util.Comparator;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * 
+ * NodeHost class used to make the mapping Node-Host.
+ * 
+ * @author Khaled Baati 26/10/2014
+ * @version version 1.1
+ */
+public class NodeHost {
+
+       /**
+        * A collection of map contained the couple (host,node)
+        */
+       public static TreeMap<Node, Host> mapHostNode = new TreeMap<Node, Host>(
+                       new Comparator<Node>() {
+                               public int compare(Node n1, Node n2) {
+                                       return String.valueOf(n1.getID()).compareTo(
+                                                       String.valueOf(n2.getID()));
+                               }
+                       });
+
+       /**
+        * The main method to make the mapping Node to Host in the
+        * {@link #mapHostNode} field
+        */
+       public static void start() {
+               Host host = null;
+               for (Integer i = 0; i < PSGSimulator.size; i++) {
+                       host = PSGPlatform.hostList[i];
+                       mapHostNode.put(Network.get(i), host);
+               }
+       }
+
+       /**
+        * This static method gets a Node instance associated with a host of your
+        * platform.
+        * 
+        * @param host
+        *            The host associated in your platform.
+        * @return The node associated.
+        */
+       public static Node getNode(Host host) {
+               for (Map.Entry<Node, Host> element : mapHostNode.entrySet()) {
+                       if (element.getValue() == host)
+                               return element.getKey();
+               }
+               return null;
+       }
+
+       /**
+        * This static method gets a host instance associated with the node of your
+        * platform.
+        * 
+        * @param node
+        *            The node associated in your platform.
+        * @return The host associated, else return null (host doesn't exist).
+        */
+       public static Host getHost(Node node) {
+               for (Map.Entry<Node, Host> element : mapHostNode.entrySet()) {
+                       if (element.getKey() == node)
+                               return element.getValue();
+               }
+               return null;
+       }
+}
diff --git a/contrib/psg/src/psgsim/PSGDynamicNetwork.java b/contrib/psg/src/psgsim/PSGDynamicNetwork.java
new file mode 100644 (file)
index 0000000..f4bb3b1
--- /dev/null
@@ -0,0 +1,45 @@
+package psgsim;
+
+import org.simgrid.msg.Host;
+import org.simgrid.msg.HostNotFoundException;
+
+import peersim.core.Node;
+
+/**
+ * 
+ * This class can change the size of networks by adding and removing nodes, as
+ * {@link peersim.dynamics.DynamicNetwork} in peersim.
+ * 
+ * @author Khaled Baati 09/02/2015
+ * @version version 1.1
+ */
+public class PSGDynamicNetwork {
+
+       /**
+        * Removes the node from the network.
+        * 
+        * @param node
+        *            the node to be removed
+        */
+       public static void remove(Node node) {
+               // NodeHost.getHost(node).off();
+               // Host h=NodeHost.mapHostNode.get(node);
+               // NodeHost.mapHostNode.remove(node);
+               PSGSimulator.size = PSGSimulator.size - 1;
+       }
+
+       /**
+        * Adds a node to the network.
+        * 
+        * @param node
+        *            the node to be added
+        * @throws HostNotFoundException 
+        */
+       public static void add(Node node) throws HostNotFoundException {
+               Host host = PSGPlatform.hostList[(int) node.getID()];
+               NodeHost.mapHostNode.put(node, host);
+               if (PSGPlatform.interfED)
+                       new PSGProcessEvent(host, host.getName(), null).start();
+               PSGSimulator.size = PSGSimulator.size + 1;
+       }
+}
diff --git a/contrib/psg/src/psgsim/PSGPlatform.java b/contrib/psg/src/psgsim/PSGPlatform.java
new file mode 100644 (file)
index 0000000..90c7c87
--- /dev/null
@@ -0,0 +1,329 @@
+package psgsim;
+
+import java.io.*;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.jdom2.*;
+import org.jdom2.output.*;
+import org.simgrid.msg.Host;
+import org.simgrid.msg.Msg;
+
+import peersim.config.Configuration;
+import peersim.core.Control;
+import peersim.core.Protocol;
+
+/**
+ * A class store different configuration information for simulation. It creates
+ * the deployment file according to this informations.
+ * 
+ * @author Khaled Baati 26/10/2014
+ * @version version 1.1
+ */
+
+public class PSGPlatform {
+
+       enum timeUnit {
+               us, ms, sec;
+       }
+
+       /** unit of measure. **/
+       static int unit;
+
+       /** the clock. **/
+       static double time;
+
+       /** the default unit of measure **/
+       static final String sec = "sec";
+
+       /** All protocols defined in the configuration file. **/
+       static Protocol[] protocolsName;
+
+       /** A numeric identifier associated for each protocol. **/
+       static int[] pid;
+
+       /** List of hos.t **/
+       static Host[] hostList;
+
+       /** A collection map represents the Control and its associated step. **/
+       static Map<Control, Double> controlStepMap = new LinkedHashMap<Control, Double>();
+
+       /** A collection map represents the protocol and its associated pid. **/
+       static TreeMap<Protocol, Integer> protocolsPidsMap = new TreeMap<Protocol, Integer>(
+                       new Comparator<Protocol>() {
+                               public int compare(Protocol p1, Protocol p2) {
+                                       return p1.toString().compareTo(p2.toString());
+                               }
+                       });
+
+       /** A collection map represents all CDProtocol and its associated step **/
+       static TreeMap<Protocol, Double> cdProtocolsStepMap = new TreeMap<Protocol, Double>(
+                       new Comparator<Protocol>() {
+                               public int compare(Protocol p1, Protocol p2) {
+                                       return p1.toString().compareTo(p2.toString());
+                               }
+                       });
+       /** the default platform file **/
+       static final String platformFile = "platforms/psg.xml";
+
+       /** the deployment file **/
+       static final String deploymentFile = "deployment.xml";
+
+       static Element racine;
+       static Document document;
+       static boolean interfED = false;
+       static boolean interfCD = false;
+
+       /** Prepare the deployment file **/
+       static {
+               DocType dtype = new DocType("platform",
+                               "http://simgrid.gforge.inria.fr/simgrid.dtd");
+               racine = new Element("platform");
+               document = new Document(racine, dtype);
+               Attribute version = new Attribute("version", "3");
+               racine.setAttribute(version);
+       }
+
+       // ========================== methods ==================================
+       // =====================================================================
+
+       /**
+        * Convert PS unit time to Simgrid unit time
+        * 
+        * @param valeur
+        *            the value to convert
+        * @return time converted
+        */
+       public static double psToSgTime(long valeur) {
+               timeUnit unit = unit();
+               switch (unit) {
+               case us:
+                       return ((double) valeur) / 1000000;
+               case ms:
+                       return ((double) valeur) / 1000;
+               default:
+                       return (double) valeur;
+
+               }
+       }
+
+       /**
+        * Convert Simgrid unit time to PS unit time
+        * 
+        * @param valeur
+        *            the value to convert
+        * @return time converted
+        */
+       public static long sgToPsTime(double valeur) {
+               timeUnit unit = unit();
+               switch (unit) {
+               case us:
+                       return (long) valeur * 1000000;
+               case ms:
+                       return (long) valeur * 1000;
+               default:
+                       return (long) valeur;
+
+               }
+       }
+
+       /**
+        * 
+        * @return the duration of simulation.
+        */
+       public static long getDuration() {
+               return Configuration.getLong("simulation.duration");
+       }
+
+       /**
+        * 
+        * @return PeerSim Time
+        */
+       public static long getTime() {
+               return sgToPsTime(Msg.getClock());
+       }
+
+       /**
+        * 
+        * @return the Simgrid Clock
+        */
+       public static double getClock() {
+               return Msg.getClock();
+       }
+
+       /**
+        * Load and run initializers.
+        */
+       public static void init() {
+               Object[] inits = Configuration.getInstanceArray("init");
+               String names[] = Configuration.getNames("init");
+               for (int i = 0; i < inits.length; ++i) {
+                       System.err.println("- Running initializer " + names[i] + ": "
+                                       + inits[i].getClass().toString());
+                       ((Control) inits[i]).execute();
+               }
+       }
+
+       /**
+        * Load all controls and stores them in {@link #controlStepMap} collection
+        * to be scheduled, and executed in {@link psgsim.PSGProcessController}.
+        */
+       public static void control() {
+               // load controls
+               String[] names = Configuration.getNames("control");
+               Control control;
+               for (int i = 0; i < names.length; ++i) {
+                       control = (Control) Configuration.getInstance(names[i]);
+                       Long stepControl = Configuration.getLong(names[i] + "." + "step");
+                       controlStepMap.put(control, psToSgTime(stepControl));
+               }
+       }
+
+       /**
+        * Lookup all protocols in the configuration file
+        */
+       public static void protocols() {
+               String[] names = Configuration.getNames("protocol");
+               Class[] interfaces;
+               protocolsName = new Protocol[names.length];
+               pid = new int[names.length];
+               boolean save = false;
+               for (int i = 0; i < names.length; i++) {
+                       protocolsName[i] = (Protocol) Configuration.getInstance(names[i]);
+                       if (i == names.length - 1)
+                               save = true;
+                       userProtocol(protocolsName[i], names[i], save);
+                       pid[i] = i;
+                       protocolsPidsMap.put(protocolsName[i], pid[i]);
+               }
+
+       }
+
+       /**
+        * Lookup CDProtocol and EDProtocol among all protocols
+        * 
+        * @param prot
+        *            the protocol class
+        * @param names
+        *            the protocol name
+        * @param save
+        *            parameter equal true when parsing all protocols
+        */
+       public static void userProtocol(Protocol prot, String names, boolean save) {
+               Class[] interfaces = prot.getClass().getInterfaces();
+               for (int j = 0; j < interfaces.length; j++) {
+                       if (interfaces[j].getName().endsWith("EDProtocol")) {
+                               interfED = true;
+                       }
+                       if (interfaces[j].getName().endsWith("CDProtocol")) {
+                               String protName = names.substring("protocol".length() + 1);
+                               long step = Configuration.getLong("protocol" + "." + protName
+                                               + "." + "step");
+                               cdProtocolsStepMap.put(prot, psToSgTime(step));
+                       }
+               }
+               if (save) {
+                       edProt();
+               }
+       }
+
+       /**
+        * 
+        */
+       private static void edProt() {
+               Host hostVal;
+               hostList = Host.all();
+               for (int i = 0; i < PSGSimulator.size; i++) {
+                       hostVal = hostList[i];
+                       Element process = new Element("process");
+                       racine.addContent(process);
+                       Attribute host = new Attribute("host", hostVal.getName());
+                       Attribute function = new Attribute("function",
+                                       "psgsim.PSGProcessEvent");
+                       process.setAttribute(host);
+                       process.setAttribute(function);
+               }
+               save(deploymentFile);
+
+       }
+
+       /**
+        * 
+        */
+       @Deprecated
+       private static void cdProt() {
+               for (int i = 0; i < PSGSimulator.size; i++) {
+                       Element process = new Element("process");
+                       racine.addContent(process);
+                       Attribute host = new Attribute("host", String.valueOf(i));
+                       Attribute function = new Attribute("function",
+                                       "psgsim.PSGProcessCycle");
+                       process.setAttribute(host);
+                       process.setAttribute(function);
+
+               }
+               save("deployment.xml");
+
+       }
+
+       /**
+        * Reads given configuration property: "platform". If not found, returns the
+        * default value.
+        * 
+        * @return the platform file
+        */
+       public static String platformFile() {
+               String defFile = platformFile;
+               String file = Configuration.getString("platform", defFile);
+               return file;
+       }
+
+       /**
+        * Reads given configuration property: "unit". If not found, returns the
+        * default value (ms).
+        * 
+        * @return the unit of measure
+        */
+       public static timeUnit unit() {
+               String defUnit = sec;
+               String unit = Configuration.getString("unit", defUnit);
+               timeUnit t = timeUnit.valueOf(unit);
+               return t;
+       }
+
+       /**
+        * Create the deployment file
+        * 
+        * @param file
+        *            the name of the deployment file
+        */
+       public static void save(String file) {
+               try {
+                       // On utilise ici un affichage classique avec getPrettyFormat()
+                       XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
+                       out.output(document, new FileOutputStream(file));
+               } catch (java.io.IOException e) {
+               }
+       }
+
+       /**
+        * Delete the deployment file
+        * 
+        * @param path
+        *            the path of the deployment file
+        */
+       public static void delete(String path) {
+               File file = new File(path);
+               try {
+                       file.delete();
+               } catch (Exception e) {
+                       System.err.println("deployment file not found");
+
+               }
+               System.err.println(path + "file deleted");
+
+       }
+
+}
diff --git a/contrib/psg/src/psgsim/PSGProcessController.java b/contrib/psg/src/psgsim/PSGProcessController.java
new file mode 100644 (file)
index 0000000..d587691
--- /dev/null
@@ -0,0 +1,68 @@
+package psgsim;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.simgrid.msg.Host;
+import org.simgrid.msg.MsgException;
+
+import peersim.core.Control;
+
+/**
+ * This class executes all controls object scheduled in the
+ * {@link PSGPlatform#controlStepMap} collection.
+ * 
+ * @author Khaled Baati 10/12/2014
+ * @version version 1.1
+ */
+public class PSGProcessController extends org.simgrid.msg.Process {
+       
+       private Map<Control, Double> controlStepMapTmp = new LinkedHashMap<Control, Double>();
+
+       public PSGProcessController(Host host, String name, String[] args) {
+               super(host, name, null);
+       }
+
+       @Override
+       public void main(String[] args) throws MsgException {
+               Double nextControlEvent;
+               for (Map.Entry<Control, Double> entry : PSGPlatform.controlStepMap
+                               .entrySet()) {
+                       controlStepMapTmp.put(entry.getKey(), entry.getValue());
+               }
+               while (PSGPlatform.getTime() <= PSGPlatform.getDuration()) {
+                       for (Map.Entry<Control, Double> entrytmp : controlStepMapTmp
+                                       .entrySet()) {
+                               Control cle = entrytmp.getKey();
+                               Double valeur = entrytmp.getValue();
+                               if (PSGPlatform.getTime() % valeur == 0) {
+                                       cle.execute();
+                                       if (PSGPlatform.getTime() != 0)
+                                               for (Map.Entry<Control, Double> entry : PSGPlatform.controlStepMap
+                                                               .entrySet()) {
+                                                       if (cle == entry.getKey())
+                                                               controlStepMapTmp.replace(cle, valeur, valeur
+                                                                               + entry.getValue());
+
+                                               }
+                               }
+                       }
+                       nextControlEvent = next();
+                       if (nextControlEvent + PSGPlatform.getTime() >= PSGPlatform.getDuration()) {
+                               break;
+                       } else {
+                               waitFor(nextControlEvent);
+                       }
+               }
+       }
+
+       private Double next() {
+               Double min = controlStepMapTmp.values().iterator().next();
+               for (Map.Entry<Control, Double> entry : controlStepMapTmp.entrySet()) {
+                       Double valeur = (entry.getValue() - PSGPlatform.getClock());
+                       if (min > valeur)
+                               min = valeur;
+               }
+
+               return min;
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/psgsim/PSGProcessCycle.java b/contrib/psg/src/psgsim/PSGProcessCycle.java
new file mode 100644 (file)
index 0000000..e0931b1
--- /dev/null
@@ -0,0 +1,59 @@
+package psgsim;
+
+import java.util.Map.Entry;
+
+import org.simgrid.msg.Host;
+import peersim.cdsim.CDProtocol;
+import peersim.core.Node;
+import peersim.core.Protocol;
+
+/**
+ * This class handle an event of type NextCycleEvent, received on the protocol
+ * identified by a pid among all CDProtocols defined in the
+ * {@link PSGPlatform#cdProtocolsStepMap} collection.
+ * <p>
+ * It executes the nextCyle method associated to this protocol.
+ * 
+ * @author Khaled Baati 27/10/2014
+ * @version version 1.1
+ */
+public class PSGProcessCycle {
+
+       /**
+        * Executes the nextCycle method of the CDprotocol with the appropriate
+        * parameters, and schedules the next call using {@link PSGSimulator#add}.
+        * 
+        * @param host
+        *            the host on which this component is run
+        * @param name
+        *            the host's name
+        * @param delay
+        *            the start time
+        * @param event
+        *            the actual event
+        * @param pid
+        *            the protocol identifier
+        */
+       public static void nextCycle(Host host, String name, double delay,
+                       Object event, int pid) {
+               CDProtocol cdp = null;
+               Node node = NodeHost.getNode(host);
+               cdp = (CDProtocol) node.getProtocol(pid);
+               cdp.nextCycle(node, pid);
+               PSGTransport.flush();
+               for (Entry<Protocol, Double> entry : PSGPlatform.cdProtocolsStepMap
+                               .entrySet()) {
+                       Double step = entry.getValue();
+                       for (Entry<Protocol, Integer> p : PSGPlatform.protocolsPidsMap
+                                       .entrySet()) {
+                               if (p.getValue() == pid) {
+                                       break;
+                               }
+                       }
+                       if (PSGPlatform.getTime() <= PSGPlatform.getDuration() && host.isOn()) {
+                               PSGSimulator.add(PSGPlatform.sgToPsTime(step), event, node, pid);
+                       }
+               }
+       }
+
+}
diff --git a/contrib/psg/src/psgsim/PSGProcessEvent.java b/contrib/psg/src/psgsim/PSGProcessEvent.java
new file mode 100644 (file)
index 0000000..cc4f73c
--- /dev/null
@@ -0,0 +1,62 @@
+package psgsim;
+
+import org.simgrid.msg.Host;
+import org.simgrid.msg.MsgException;
+
+import peersim.core.Node;
+import peersim.edsim.EDProtocol;
+
+/**
+ * This class extends {@link org.simgrid.msg.Process} which creates a process
+ * for each host (corresponding to node in peersim) in the system.
+ * <p>
+ * The main method of this class is to handle events received, by calling the
+ * processEvent method on the corresponding node and pid.
+ * <p>
+ * See {@link peersim.edsim.EDProtocol#processEvent}
+ * 
+ * @author Khaled Baati 28/10/2014
+ * @version version 1.1
+ */
+public class PSGProcessEvent extends org.simgrid.msg.Process {
+       /** The delivered event **/
+       private PSGTask task;
+       /** The current protocol **/
+       private EDProtocol prot;
+       /** The identifier of the current protocol **/
+       private int pid;
+
+       /**
+        * Constructs a new process from the name of a host.
+        * 
+        * @param host
+        *            the local host to create according to the active node in
+        *            peersim
+        * @param name
+        *            the host's name
+        * @param args
+        *            The arguments of main method of the process.
+        */
+       public PSGProcessEvent(Host host, String name, String[] args) {
+               super(host, name, args);
+       }
+
+       @Override
+       public void main(String[] args) throws MsgException {
+               Node node = NodeHost.getNode(getHost());
+               Host.setAsyncMailbox(getHost().getName());
+               while (PSGPlatform.getTime() < PSGPlatform.getDuration()) {
+                       task = null;
+                       task = (PSGTask) PSGTask.receive(Host.currentHost().getName(),
+                                       PSGPlatform.psToSgTime(PSGPlatform.getDuration() - PSGPlatform.getTime()-1));
+                       if (task != null && PSGPlatform.getTime() < PSGPlatform.getDuration()) {
+                               pid = task.getPid();
+                               prot = (EDProtocol) node.getProtocol(pid);
+                               prot.processEvent(node, pid, task.getEvent());
+                               PSGTransport.flush();
+                       } else
+                               break;
+               }
+       }
+
+}
diff --git a/contrib/psg/src/psgsim/PSGProcessLauncher.java b/contrib/psg/src/psgsim/PSGProcessLauncher.java
new file mode 100644 (file)
index 0000000..97d89c0
--- /dev/null
@@ -0,0 +1,74 @@
+package psgsim;
+
+import org.simgrid.msg.Host;
+import org.simgrid.msg.MsgException;
+
+import peersim.core.Node;
+import peersim.edsim.EDProtocol;
+import peersim.edsim.NextCycleEvent;
+
+/**
+ * This class extends {@link org.simgrid.msg.Process}, it creates a process for
+ * each event added in {@link PSGSimulator#add}.
+ * <p>
+ * This class performs to launch the appropriate call according to the type of
+ * the event;
+ * <p>
+ * - A NextCycleEvent: the event will be delivered to the
+ * {@link PSGProcessCycle} for treatment.
+ * <p>
+ * - Otherwise the event is delivered to the destination protocol, that must
+ * implement {@link EDProtocol}, and the processEvent method is executed.
+ * 
+ * @author Khaled Baati 12/11/2014
+ * @version version 1.1
+ */
+public class PSGProcessLauncher extends org.simgrid.msg.Process {
+       private EDProtocol prot = null;
+       private int pid;
+       private double delay;
+       private Object event;
+       private Host host;
+
+       /**
+        * Constructs a new process from the name of a host and with the associated
+        * parameters
+        * 
+        * @param host
+        *            the local host
+        * @param name
+        *            the host's name
+        * @param delay
+        *            the start time of the process
+        * @param event
+        *            the event added to the simulator
+        * @param pid
+        *            the protocol identifier
+        */
+       public PSGProcessLauncher(Host host, String name, double delay, Object event,
+                       int pid) {
+               super(host, name, null, delay, -1);
+               this.host = host;
+               this.pid = pid;
+               this.event = event;
+               this.delay = delay;
+       }
+
+       public PSGProcessLauncher(Host host, String name, String[] args) {
+
+       }
+
+       @Override
+       public void main(String[] args) throws MsgException {
+               Node node = NodeHost.getNode(host);
+               if (event instanceof NextCycleEvent) {
+                       PSGProcessCycle.nextCycle(Host.currentHost(), host.getName(),
+                                       delay, event, pid);
+               } else {
+                       prot = (EDProtocol) node.getProtocol(pid);
+                       prot.processEvent(node, pid, event);
+                       PSGTransport.flush();
+               }
+               waitFor(500);
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/psgsim/PSGSimulator.java b/contrib/psg/src/psgsim/PSGSimulator.java
new file mode 100644 (file)
index 0000000..4d45d4e
--- /dev/null
@@ -0,0 +1,98 @@
+package psgsim;
+
+import org.simgrid.msg.Host;
+import org.simgrid.msg.HostNotFoundException;
+import org.simgrid.msg.Msg;
+import org.simgrid.msg.NativeException;
+
+import peersim.core.CommonState;
+import peersim.core.Network;
+import peersim.core.Node;
+
+/**
+ * This is the main entry point to Simgrid simulator. This class loads the
+ * different parameters and initializes the simulation.
+ * 
+ * @author Khaled Baati 14/10/2014
+ * @version version 1.1
+ */
+public class PSGSimulator {
+       public static int size;
+
+       static {
+               Network.reset();
+               size = Network.size();
+       }
+
+       // ========================== methods ==================================
+       // =====================================================================
+
+       /**
+        * Adds a new event to be scheduled, specifying the number of time units of
+        * delay (in seconds), the node and the protocol identifier to which the
+        * event will be delivered. A {@link psgsim.PSGProcessLauncher} process will
+        * be created according to this event.
+        * 
+        * @param delay
+        *            The number of time units (seconds in simgrid) before the event
+        *            is scheduled.
+        * @param event
+        *            The object associated to this event
+        * @param src
+        *            The node associated to the event.
+        * @param pid
+        *            The identifier of the protocol to which the event will be
+        *            delivered
+        */
+       public static void add(long delay, Object event, Node src, int pid) {
+               Host host = NodeHost.getHost(src);
+               double startTime = PSGPlatform.psToSgTime(delay) + Msg.getClock(); 
+               if (startTime < PSGPlatform.psToSgTime(PSGPlatform.getDuration()) ) {
+                       try {
+                               /**
+                                * random instruction associated to Heap.add(...) method in
+                                * peersim.edsim
+                                **/
+                               CommonState.r.nextInt(1 << 8);
+                               new PSGProcessLauncher(host, host.getName(), startTime, event,
+                                               pid).start();
+                       } catch (HostNotFoundException e) {
+                               System.err.println("Host not found");
+                       }
+               }
+
+       }
+
+       // ========================== main method ==================================
+       // =====================================================================
+       public static void main() throws NativeException, HostNotFoundException {
+
+               String platformfile = PSGPlatform.platformFile();
+               System.err.println(platformfile + " loaded");
+               String[] arguments = { platformfile, "deployment.xml" };
+               Msg.init(arguments);
+
+               /** construct the platform */
+               Msg.createEnvironment(arguments[0]);
+
+               PSGPlatform.protocols();
+
+               /** deploy the application **/
+               Msg.deployApplication(arguments[1]);
+
+               /** construct the host-node mapping **/
+               NodeHost.start();
+
+               /** Process Controller **/
+               PSGPlatform.control();
+               new PSGProcessController(PSGPlatform.hostList[0],
+                               PSGPlatform.hostList[0].getName(), null).start();
+
+               /** Load and execute the initializers classes in the configuration file **/
+               PSGPlatform.init();
+
+               PSGPlatform.delete("deployment.xml");
+               /** execute the simulation. **/
+               Msg.run();
+       }
+}
diff --git a/contrib/psg/src/psgsim/PSGTask.java b/contrib/psg/src/psgsim/PSGTask.java
new file mode 100644 (file)
index 0000000..6d25e2c
--- /dev/null
@@ -0,0 +1,85 @@
+package psgsim;
+
+import org.simgrid.msg.HostFailureException;
+import org.simgrid.msg.Task;
+import org.simgrid.msg.TimeoutException;
+import org.simgrid.msg.TransferFailureException;
+
+/**
+ * The PSGTask includes all the parameters of sending a message as the size, the
+ * compute duration and the protocol identifier.
+ * 
+ * @author Khaled Baati 28/10/2014
+ * @version version 1.1
+ */
+public class PSGTask extends org.simgrid.msg.Task {
+       /** The Message to be sent **/
+       private Object event;
+       /** The protocol identifier **/
+       private int pid;
+
+       /**
+        * Construct a new task to be sent.
+        * 
+        * @param name
+        *            The name of task
+        * @param computeDuration
+        *            The compute duration
+        * 
+        * @param messageSize
+        *            The size of the message
+        * @param event
+        *            The message to be sent
+        * @param pid
+        *            The protocol identifier
+        */
+       public PSGTask(String name, double computeDuration, double messageSize,
+                       Object event, int pid) {
+               super(name, computeDuration, messageSize);
+               this.event = event;
+               this.pid = pid;
+       }
+
+       /**
+        * 
+        * @return the protocol identifier
+        */
+       public int getPid() {
+               return pid;
+       }
+
+       /**
+        * 
+        * @return the message
+        */
+       public Object getEvent() {
+               return event;
+       }
+
+       /**
+        * Retrieves next task on the mailbox identified by the specified name (wait
+        * at most timeout seconds)
+        * 
+        * @param mailbox
+        *            the mailbox on where to receive the task
+        * @param timeout
+        *            the timeout to wait for receiving the task
+        * @return the task
+        */
+       public static Task receive(String mailbox, double timeout) {
+               double time = PSGPlatform.getClock();
+               if (time + timeout > PSGPlatform.getClock()) {
+                       try {
+                               return receive(mailbox, timeout, null);
+                       } catch (TimeoutException e) {
+                       } catch (TransferFailureException e) {
+                               e.printStackTrace();
+                       } catch (HostFailureException e) {
+                               e.printStackTrace();
+                       }
+               }
+               return null;
+
+       }
+
+}
diff --git a/contrib/psg/src/psgsim/PSGTransport.java b/contrib/psg/src/psgsim/PSGTransport.java
new file mode 100644 (file)
index 0000000..db964b4
--- /dev/null
@@ -0,0 +1,115 @@
+package psgsim;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import peersim.config.Configuration;
+import peersim.config.IllegalParameterException;
+import peersim.core.CommonState;
+import peersim.core.Node;
+import peersim.transport.Transport;
+
+/**
+ * PSGTransport is the transport layer. it is responsible for sending messages.
+ * 
+ * @author Khaled Baati 28/10/2014
+ * @version 1.1
+ */
+public class PSGTransport implements Transport {
+
+       private static double computeDuration = 0;
+       private PSGTask task;
+       private static Map<PSGTask, String> taskToSend = new LinkedHashMap<PSGTask, String>();
+
+       /**
+        * String name of the parameter used to configure the minimum latency. * @config
+        */
+       private static final String PAR_MINDELAY = "mindelay";
+
+       /**
+        * String name of the parameter used to configure the maximum latency.
+        * Defaults to {@value #PAR_MINDELAY}, which results in a constant delay.
+        * 
+        * @config
+        */
+       private static final String PAR_MAXDELAY = "maxdelay";
+
+       /** Minimum delay for message sending */
+       private long min;
+       /** Maximum delay for message sending */
+       private long max;
+
+       /**
+        * Difference between the max and min delay plus one. That is, max delay is
+        * min+range-1.
+        */
+       private long range;
+
+       public PSGTransport() {
+
+       }
+
+       public PSGTransport(String prefix) {
+               min = Configuration.getLong(prefix + "." + PAR_MINDELAY);
+               max = Configuration.getLong(prefix + "." + PAR_MAXDELAY, min);
+               if (max < min)
+                       throw new IllegalParameterException(prefix + "." + PAR_MAXDELAY,
+                                       "The maximum latency cannot be smaller than the minimum latency");
+               range = max - min + 1;
+       }
+
+       /**
+        * Returns <code>this</code>. This way only one instance exists in the
+        * system that is linked from all the nodes. This is because this protocol
+        * has no node specific state.
+        */
+       public Object clone() {
+               return this;
+       }
+
+       @Override
+       public void send(Node src, Node dest, Object msg, int pid) {
+               double commSizeLat = 0;
+               /**
+                * random instruction associated to UniformRandomTransport.send(...)
+                * method in peersim.transport
+                **/
+               long delay = (range == 1 ? min : min + CommonState.r.nextLong(range));
+               CommonState.r.nextInt(1 << 8);
+               if (msg instanceof Sizable) {
+                       commSizeLat = ((Sizable) msg).getSize();
+               }
+
+               task = new PSGTask("task sender_" + src.getID(), computeDuration,
+                               commSizeLat, msg, pid);
+               taskToSend.put(this.task, NodeHost.getHost(dest).getName());
+
+       }
+
+       /**
+        * Process for sending all messages in the queue.
+        */
+       public static void flush() {
+               Map<PSGTask, String> taskToSendCopy = new LinkedHashMap<PSGTask, String>();
+               for (Map.Entry<PSGTask, String> entry : taskToSend.entrySet()) {
+                       taskToSendCopy.put(entry.getKey(), entry.getValue());
+               }
+               taskToSend.clear();
+               for (Map.Entry<PSGTask, String> entry : taskToSendCopy.entrySet()) {
+                       PSGTask task = entry.getKey();
+                       String dest = entry.getValue();
+                       task.dsend(dest);
+               }
+               taskToSendCopy.clear();
+
+       }
+
+       @Override
+       public long getLatency(Node src, Node dest) {
+               /**
+                * random instruction associated to
+                * UniformRandomTransport.getLatency(...) method in peersim.transport
+                **/
+               return (range == 1 ? min : min + CommonState.r.nextLong(range));
+       }
+}
diff --git a/contrib/psg/src/psgsim/Sizable.java b/contrib/psg/src/psgsim/Sizable.java
new file mode 100644 (file)
index 0000000..16196f6
--- /dev/null
@@ -0,0 +1,18 @@
+package psgsim;
+
+/**
+ * An interface which defines a size for the message or the event to be sent. If you
+ * wish that your message has a size, your class message must implements this
+ * interface and defines a size parameter in the constructor.
+ * 
+ * @author Khaled Baati 05/02/2015
+ * @version 1.1
+ * 
+ */
+public interface Sizable {
+       /**
+        * 
+        * @return The size of the message
+        */
+       public double getSize();
+}
diff --git a/contrib/psg/test.sh b/contrib/psg/test.sh
new file mode 100755 (executable)
index 0000000..f5b7f09
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+if [ $(uname -m) = "i686" ]; then
+       eval ulimit -s 64
+else 
+       eval ulimit -s 128
+fi
+
+echo -e "\n";
+echo '------------- Execute the edaggregation example under PSG -------------';
+echo -e "\n";
+java -Xmx1024m -cp lib.jar:classes peersim.Simulator configs/edaggregationPSG.txt
+echo -e "\n";
+echo '------------- Execute the edaggregation example under PS -------------';
+echo -e "\n";
+java -Xmx1024m -cp lib.jar:classes peersim.Simulator configs/edaggregation.txt
+echo -e "\n";
+echo '------------- Execute the chord example under PSG -------------';
+echo -e "\n";
+java -Xmx1024m -cp lib.jar:classes peersim.Simulator configs/chordPSG.txt
+echo -e "\n";
+echo '------------- Execute the chord example under PS -------------';
+echo -e "\n";
+java -Xmx1024m -cp lib.jar:classes peersim.Simulator configs/chord.txt
+echo -e "\n";
+echo '------------- Compare the 2 results PS and PSG -------------';
+echo -e "\n";
+
+cd outputs
+
+ListeRep="$(find * -type d -prune)"   # liste des repertoires
+for Rep in ${ListeRep}; do     
+       cd $Rep
+       VAR=$(diff ps.txt psg.txt)
+       if [ "${VAR}"1 = 1 ]
+               then
+                echo The results of diff "for" the $Rep example is '.............:)';
+       else
+                echo The results of diff "for" the $Rep example is '.............:(';
+       fi
+       cd ..
+done
+echo -e "\n";
+exit 0
+
diff --git a/contrib/psg/tutorial.pdf b/contrib/psg/tutorial.pdf
new file mode 100644 (file)
index 0000000..591649f
Binary files /dev/null and b/contrib/psg/tutorial.pdf differ