/* * 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.File; import java.io.FileNotFoundException; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Scanner; import de.tud.kom.p2psim.api.network.SimNetInterface; import de.tud.kom.p2psim.api.network.SimNetworkComponent; import de.tud.kom.p2psim.api.scenario.ConfigurationException; import de.tud.kom.p2psim.api.topology.movement.MovementModel; import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator; import de.tud.kom.p2psim.impl.topology.DefaultTopology; import de.tud.kom.p2psim.impl.topology.movement.modularosm.IAttractionBasedMovementAnalyzer; import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.AttractionPointViz; import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionProvider; import de.tud.kom.p2psim.impl.topology.movement.modularosm.mapvisualization.IMapVisualization; import de.tud.kom.p2psim.impl.topology.util.PositionVector; import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector; 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.Time; import de.tudarmstadt.maki.simonstrator.api.component.LifecycleComponent; public class TracefileMovementModel implements MovementModel, EventHandler { public static String tracefileFolder ="smarter/tracefiles/"; public static String tracefilePrefix = "smarterTraceFile-"; public static long GPS_MISSING_TRACE_THRESHOLD = 60; public static int ZERO_TO_2 = 0; public static int _2_to_5 = 0; public static int _5_to_10 = 0; public static int TEN_TO_THIRTY = 0; public static int THIRTY_TO_SIXTY = 0; public static int SIXTY_TO_120 = 0; public static int _120_TO_300 = 0; public static int _300_TO_600 = 0; public static int ABOVE_600 = 0; protected final int EVENT_MOVE = 1; protected final PositionVector DEFAULT_POSITION = new PositionVector(-1000, -1000); protected long timeBetweenMoveOperations; protected IMapVisualization mapVisualization; protected IAttractionProvider attractionGenerator; protected AttractionPointViz attractionpointVisualization; protected boolean initialized = false; private final LinkedHashMap> components; private final static LinkedHashMap componentToStepSize = new LinkedHashMap(); private final LinkedHashSet unusedComponents; private LinkedList tracefiles; private boolean first = true; public TracefileMovementModel() { components = new LinkedHashMap>(); tracefiles = new LinkedList(); unusedComponents = new LinkedHashSet(); } public void initialize() { if(initialized) { return; } File folder = new File(tracefileFolder); if (!folder.exists()) { throw new UnsupportedOperationException("Tracefile folder not found"); } for(File tracefile : folder.listFiles()) { if(tracefile.getName().contains(tracefilePrefix)) { tracefiles.add(tracefile); } } if (mapVisualization != null) { VisualizationInjector.injectComponent(mapVisualization); } if (attractionpointVisualization != null) { attractionpointVisualization.setAttractionPoints(new LinkedList<>(attractionGenerator.getAttractionPoints())); VisualizationInjector.injectComponent(attractionpointVisualization); } initialized = true; Event.scheduleWithDelay(timeBetweenMoveOperations, this, null, EVENT_MOVE); } @Override public void eventOccurred(Object content, int type) { if (type == EVENT_MOVE) { move(); } } private void move() { if(first) { components.forEach((component, steps) -> { shutdownComponent(component); }); unusedComponents.forEach((component) -> { shutdownComponent(component); }); } // as the files contain the timestamp in seconds, the current time needs to be converted in seconds long currentTime = Time.getCurrentTime() / Time.SECOND; LinkedList toRemove = new LinkedList<>(); components.forEach((component, steps) -> { Step step = steps.peek(); if (step != null) { if(currentTime < step.timestamp) { if(DefaultTopology.isWithinWorldBoundaries(component.getRealPosition())) { if(currentTime + GPS_MISSING_TRACE_THRESHOLD >= step.timestamp) { if(component.getRealPosition().distanceTo(new PositionVector(step.x, step.y)) > GPS_MISSING_TRACE_THRESHOLD * 2) { shutdownComponent(component); } // do nothing for smoothing? // TODO else { int stepcount = componentToStepSize.get(component); stepcount++; componentToStepSize.put(component, stepcount); } } else { if(DefaultTopology.isWithinWorldBoundaries(component.getRealPosition())) { // TODO long delta = step.timestamp - currentTime + GPS_MISSING_TRACE_THRESHOLD; if(delta > 0 && delta <= 2) { ZERO_TO_2++; } else if(delta > 2 && delta <= 5) { _2_to_5++; } else if(delta > 5 && delta <= 10) { _5_to_10++; } else if(delta > 10 && delta <= 30) { TEN_TO_THIRTY++; } else if(delta > 30 && delta <= 60) { THIRTY_TO_SIXTY++; } else if(delta > 60 && delta <= 120) { SIXTY_TO_120++; } else if(delta > 120 && delta <= 300) { _120_TO_300++; } else if(delta > 300 && delta <= 600) { _300_TO_600++; } else if(delta > 600) { ABOVE_600++; } shutdownComponent(component); } } } } else { step = steps.pop(); // TODO int stepcount = componentToStepSize.get(component); stepcount++; componentToStepSize.put(component, stepcount); if(!DefaultTopology.isWithinWorldBoundaries(component.getRealPosition())) { component.updateCurrentLocation(new PositionVector(step.x, step.y)); startupComponent(component); } else { component.updateCurrentLocation(new PositionVector(step.x, step.y)); } } } else { toRemove.add(component); } }); for (SimLocationActuator simLocationActuator : toRemove) { components.remove(simLocationActuator); shutdownComponent(simLocationActuator); } Event.scheduleWithDelay(timeBetweenMoveOperations, this, null, EVENT_MOVE); if(first) { // Inform analyzer of resolved movement if(Monitor.hasAnalyzer(IAttractionBasedMovementAnalyzer.class)) { Monitor.getOrNull(IAttractionBasedMovementAnalyzer.class).onAllNodeInitializationCompleted(components.keySet()); } first =false; } } private void shutdownComponent(SimLocationActuator node) { SimNetworkComponent net = (SimNetworkComponent) node.getHost().getNetworkComponent(); for (SimNetInterface netI : net.getSimNetworkInterfaces()) { if (netI.isOnline()) { netI.goOffline(); } } try { List comps = node.getHost().getComponents(LifecycleComponent.class); for (LifecycleComponent lifecycleComponent : comps) { lifecycleComponent.stopComponent(); } } catch (Exception e) { // TODO: handle exception } node.updateCurrentLocation(new PositionVector(DEFAULT_POSITION)); } private void startupComponent(SimLocationActuator node) { SimNetworkComponent net = (SimNetworkComponent) node.getHost().getNetworkComponent(); for (SimNetInterface netI : net.getSimNetworkInterfaces()) { if (netI.isOffline()) { netI.goOnline(); } } try { List comps = node.getHost().getComponents(LifecycleComponent.class); for (LifecycleComponent lifecycleComponent : comps) { lifecycleComponent.startComponent(); } } catch (Exception e) { // TODO: handle exception } } @Override public void addComponent(SimLocationActuator actuator) { if (!initialized) { initialize(); } associateTracefile(actuator); } private void associateTracefile(SimLocationActuator actuator) { if(tracefiles.isEmpty()) { Monitor.log(this.getClass(), Level.WARN, "No unassociated trace file available. Skip.", actuator); //throw new UnsupportedOperationException("List of tracefiles is empty, thus cannot initiate the component!"); unusedComponents.add(actuator); return; } if(components.containsKey(actuator)) { throw new UnsupportedOperationException("Component was already assigned!"); } LinkedList stepQueue = new LinkedList(); File tracefile = tracefiles.pop(); Scanner filescanner; try { filescanner = new Scanner(tracefile); while(filescanner.hasNextLine()) { String line = filescanner.nextLine(); String[] split = line.split(" "); long timestamp = Long.valueOf(split[0]); //double lat = Double.valueOf(split[1]); //double lon = Double.valueOf(split[2]); double x = Double.valueOf(split[3]); double y = Double.valueOf(split[4]); Step s = new Step(timestamp, x, y); stepQueue.add(s); } filescanner.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { System.err.println(tracefile.getName()); e.printStackTrace(); } // System.out.println(actuator.getHost().getId() + " <> " + tracefile.getName()); components.put(actuator, stepQueue); componentToStepSize.put(actuator, 0); } public static int getComponentStepSize(SimLocationActuator component) { if(!componentToStepSize.containsKey(component)) { return -1; } return componentToStepSize.get(component); } @Override public void placeComponent(SimLocationActuator actuator) { // Initial placement actuator.updateCurrentLocation(new PositionVector(DEFAULT_POSITION)); } @Override public void setTimeBetweenMoveOperations(long time) { this.timeBetweenMoveOperations = time; } public void setIMapVisualization(IMapVisualization mapVisualization) { this.mapVisualization = mapVisualization; } public void setAttractionPointViz(AttractionPointViz viz) { this.attractionpointVisualization = viz; } public void setIAttractionProvider(IAttractionProvider attractionGenerator) { if (attractionGenerator == null) { throw new ConfigurationException( "AttractionGenerator is missing in ModularMovementModel!"); } this.attractionGenerator = attractionGenerator; } private class Step { public final double x; public final double y; public final long timestamp; public Step(long timestamp, double x, double y) { this.x = x; this.y = y; this.timestamp = timestamp; } @Override public String toString() { return "Step @ " + timestamp + "s -> ("+x+", "+y+")"; } } }