/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see .
*
*/
package de.tud.kom.p2psim.impl.topology.movement;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
import java.util.zip.GZIPInputStream;
import de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.simengine.Simulator;
import de.tud.kom.p2psim.impl.topology.component.DefaultTopologyComponent;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Monitor.Level;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
public class BonnMotionMovementModel extends AbstractMovementModel implements
EventHandler {
private final int EVENT_ID = 1;
private Vector mobilityTraceFiles;
private Vector mobilityConfigFiles;
private Vector offsets;
private long hostCounter;
private long movementInterval;
private PositionVector previousPosition;
private long previousTime;
private long lastNotificationTime;
private int fileCounter = 1;
@XMLConfigurableConstructor({ "movementInterval" })
public BonnMotionMovementModel(long movementInterval) {
super();
this.movementInterval = movementInterval;
this.lastNotificationTime = 0;
this.hostCounter = 1;
this.mobilityTraceFiles = new Vector();
this.mobilityConfigFiles = new Vector();
this.offsets = new Vector();
Map variables = Simulator.getConfigurator()
.getVariables();
String traceFile = variables.get("mobilityTraceFile-File-"+fileCounter);
String configFile = variables.get("mobilityConfigFile-File-"+fileCounter);
String xString = variables.get("xOffset-File-" + fileCounter);
String yString = variables.get("yOffset-File-" + fileCounter);
while (traceFile != null && configFile != null && xString != null
&& yString != null) {
this.mobilityTraceFiles.add(traceFile);
this.mobilityConfigFiles.add(configFile);
Integer xOffset = Integer.parseInt(xString);
Integer yOffset = Integer.parseInt(yString);
this.offsets.add(new PositionVector(xOffset.intValue(), yOffset
.intValue()));
fileCounter++;
traceFile = variables.get("mobilityTraceFile-File-" + fileCounter);
configFile = variables
.get("mobilityConfigFile-File-" + fileCounter);
xString = variables.get("xOffset-File-" + fileCounter);
yString = variables.get("yOffset-File-" + fileCounter);
}
checkConfiguration();
extractMovement();
}
@Override
public void move() {
// This method is not required, because the hosts are moved over an
// trace-file.
}
private void checkConfiguration() {
for (String s : mobilityConfigFiles) {
StringBuffer sBuf = new StringBuffer();
File configFile = new File(s);
Properties props = new Properties();
try {
props.load(new FileInputStream(configFile));
Map variables = Simulator.getConfigurator()
.getVariables();
// FIXME Find an alternative way to ensure correct number of
// nodes
// Check for correct dimensions
// if (Double.parseDouble(variables.get("WORLD-X")) != Double
// .parseDouble((String) props.get("x"))
// || Double.parseDouble(variables.get("WORLD-Y")) != Double
// .parseDouble((String) props.get("y"))) {
// sBuf.append("- The dimensions in the PFS-Config-File do not match the dimensions in the BonnMotion-Config-File!\n");
// }
// FIXME Find an alternative way to ensure correct number of
// nodes
// Check for correct number of nodes
// if (Integer.parseInt(variables.get("movingPeersSize")) >
// Integer
// .parseInt((String) props.get("nn"))) {
// sBuf.append("- The PFS-Config-File specifies more nodes than the BonnMotion-Config-File!\n");
// }
// Check for correct length of the simulation
if ((Simulator.getEndTime() / (double) Simulator.SECOND_UNIT) > Double
.parseDouble((String) props.get("duration"))) {
sBuf.append("- The PFS-Config-File specifies a longer simulation than the BonnMotion-Config-File!\n");
}
if (sBuf.length() > 0) {
throw new RuntimeException(sBuf.toString());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void extractMovement() {
for (int a=0;a movementInterval)) {
// calculate the direction and the time interval
// between
// the previous and the next point
direction = new PositionVector(nextPosition.getX()
- previousPosition.getX(),
nextPosition.getY()
- previousPosition.getY());
timeSpan = nextTime - previousTime;
long deltaTime = movementInterval;
Monitor.log(
BonnMotionMovementModel.class,
Level.DEBUG,
"Creating "
+ timeSpan
/ movementInterval
+ " intermediate points between "
+ previousPosition + " and " + nextPosition
+ " at time "
+ Simulator.getFormattedTime(previousTime)
+ " and "
+ Simulator.getFormattedTime(nextTime));
// add the intermediate steps
while (deltaTime < timeSpan) {
double x = previousPosition.getX() + deltaTime
/ (double) timeSpan * direction.getX();
double y = previousPosition.getY() + deltaTime
/ (double) timeSpan * direction.getY();
PositionVector interStep = new PositionVector(
x, y);
Monitor.log(
BonnMotionMovementModel.class,
Level.DEBUG,
"Creating "
+ interStep
+ " for time "
+ Simulator.getFormattedTime(deltaTime
+ previousTime));
Event.scheduleWithDelay(deltaTime
+ previousTime, this,
new BonnMotionEvent(interStep,
hostCounter), EVENT_ID);
deltaTime = deltaTime + movementInterval;
}
// Schedule the final position and set this position
// and
// time as the previous ones
Event.scheduleWithDelay(nextTime, this,
new BonnMotionEvent(nextPosition,
hostCounter), EVENT_ID);
previousPosition = nextPosition;
previousTime = nextTime;
} else {
// Schedule the final position and set this position
// and
// time as the previous ones
Event.scheduleWithDelay(nextTime, this,
new BonnMotionEvent(nextPosition,
hostCounter), EVENT_ID);
previousPosition = nextPosition;
previousTime = nextTime;
}
}
hostCounter++;
}
Monitor.log(BonnMotionMovementModel.class, Level.WARN,
"Successfully parsed " + mobilityTraceFiles.get(a)
+ " and created movement for " + (hostCounter - 1)
+ " hosts");
buf.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void eventOccurred(Object content, int type) {
if (type == EVENT_ID) {
BonnMotionEvent bme = (BonnMotionEvent) content;
Set components = getComponents();
for (SimLocationActuator comp : components) {
if (((DefaultTopologyComponent) comp).getHost().getHostId() == bme
.getHostID()) {
PositionVector newPos = bme.getNextPosition();
updatePosition(comp, newPos);
// FIXME Delete!! Only test-logger!
// log.warn(Simulator.getFormattedTime(Simulator.getCurrentTime())+" ID = " + bme.getHostID() +" pos = " + pos);
}
}
}
}
private class BonnMotionEvent {
private PositionVector nextPosition;
private long hostID;
public BonnMotionEvent(PositionVector nextPosition, long hostID) {
super();
this.nextPosition = nextPosition;
this.hostID = hostID;
}
public PositionVector getNextPosition() {
return nextPosition;
}
public long getHostID() {
return hostID;
}
}
}