/* * 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.component; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import de.tud.kom.p2psim.api.common.SimHost; import de.tud.kom.p2psim.api.linklayer.mac.PhyType; import de.tud.kom.p2psim.api.topology.Topology; import de.tud.kom.p2psim.api.topology.TopologyComponent; import de.tud.kom.p2psim.api.topology.movement.MovementModel; import de.tud.kom.p2psim.api.topology.placement.PlacementModel; import de.tud.kom.p2psim.impl.topology.util.LocalGraphView; import de.tud.kom.p2psim.impl.topology.util.LocationRequestImpl; import de.tud.kom.p2psim.impl.topology.util.PositionVector; import de.tudarmstadt.maki.simonstrator.api.common.graph.Graph; import de.tudarmstadt.maki.simonstrator.api.common.graph.IEdge; import de.tudarmstadt.maki.simonstrator.api.common.graph.INode; import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID; import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationListener; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationRequest; import de.tudarmstadt.maki.simonstrator.api.component.sis.SiSComponent; import de.tudarmstadt.maki.simonstrator.api.component.sis.SiSDataCallback; import de.tudarmstadt.maki.simonstrator.api.component.sis.exception.InformationNotAvailableException; import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSTypes; import de.tudarmstadt.maki.simonstrator.api.component.sis.SiSInformationProvider.SiSProviderHandle; import de.tudarmstadt.maki.simonstrator.api.component.sis.SiSInfoProperties; import de.tudarmstadt.maki.simonstrator.api.Event; import de.tudarmstadt.maki.simonstrator.api.EventHandler; import de.tudarmstadt.maki.simonstrator.api.component.sis.util.SiSTopologyProvider; import de.tudarmstadt.maki.simonstrator.api.component.topology.TopologyID; import de.tudarmstadt.maki.simonstrator.api.component.network.NetworkComponent.NetInterfaceName; /** * Abstract implementation of the topology component interface, to support basic * functionalities to all topology components. * * @author Julian Zobel, others before * @version 1.0, 6 Sep 2018 */ public abstract class AbstractTopologyComponent implements TopologyComponent { protected SimHost host; protected final PositionVector position; protected final Double POSITION_REQUEST_UPDATE_ACCURACY = 0.1; // accuracy for location request updates protected Topology topology; protected MovementModel movementModel; protected PlacementModel placementModel; private final boolean registerAsInformationProviderInSiS; private Map openRequests = new LinkedHashMap(); private List listeners = new LinkedList<>(); // public AbstractTopologyComponent(SimHost host, Topology topology, MovementModel movementModel, PlacementModel placementModel, boolean registerAsInformationProviderInSiS) { this.topology = topology; this.host = host; this.position = new PositionVector(0, 0); this.movementModel = movementModel; if (this.movementModel != null) { this.movementModel.addComponent(this); } this.placementModel = placementModel; if (this.placementModel != null) { this.placementModel.addComponent(this); } this.registerAsInformationProviderInSiS = registerAsInformationProviderInSiS; } @Override public void initialize() { topology.addComponent(this); movementModel.placeComponent(this); if (placementModel != null) { // retrieve the initial position of this topology component position.set(placementModel.place(this)); } if (registerAsInformationProviderInSiS) { try { final SiSComponent sis = host.getComponent(SiSComponent.class); sis.provide().nodeState(SiSTypes.PHY_LOCATION, new SiSDataCallback() { Set localID = INodeID .getSingleIDSet(getHost().getId()); @Override public Location getValue(INodeID nodeID, SiSProviderHandle providerHandle) throws InformationNotAvailableException { if (nodeID.equals(getHost().getId())) { return getLastLocation(); } else { throw new InformationNotAvailableException(); } } @Override public Set getObservedNodes() { return localID; } @Override public SiSInfoProperties getInfoProperties() { return new SiSInfoProperties(); } }); sis.provide().nodeState(SiSTypes.SPEED, new SiSDataCallback() { Set localID = INodeID .getSingleIDSet(getHost().getId()); @Override public Double getValue(INodeID nodeID, SiSProviderHandle providerHandle) throws InformationNotAvailableException { if (nodeID.equals(getHost().getId())) { return getMovementSpeed(); } else { throw new InformationNotAvailableException(); } } @Override public Set getObservedNodes() { return localID; } @Override public SiSInfoProperties getInfoProperties() { return new SiSInfoProperties(); } }); // Provide Underlay topology Event.scheduleImmediately(new EventHandler() { @Override public void eventOccurred(Object content, int type) { if (getHost().getLinkLayer().hasPhy(PhyType.WIFI)) { new SiSTopologyProvider(sis, SiSTypes.NEIGHBORS_WIFI, AbstractTopologyComponent.this, getTopologyID(NetInterfaceName.WIFI, true), AbstractTopologyComponent.class); } } }, null, 0); } catch (ComponentNotAvailableException e) { // OK } } } @Override public void shutdown() { topology = null; host = null; movementModel = null; } @Override public SimHost getHost() { return host; } @Override public Topology getTopology() { return topology; } /** * Access to the movement model * @return */ public MovementModel getMovementModel() { return movementModel; } @Override public Location getLastLocation() { /* * As we want to mimic real world behavior, the current position * snapshot is cloned to prevent information propagation due to Java. */ return position.clone(); } @Override public PositionVector getRealPosition() { return position; // no copy! See SimLocationActuator Interface Description! } @Override public void updateCurrentLocation(Location location) { boolean informListeners = false; // only inform listeners if the location has changed if(location.distanceTo(position) >= POSITION_REQUEST_UPDATE_ACCURACY) { informListeners = true; } position.set(location); if(informListeners) { for (LocationListener locationListener : listeners) { locationListener.onLocationChanged(getHost(), getLastLocation()); } } } @Override public void requestLocationUpdates(LocationRequest request, LocationListener listener) { if (openRequests.containsKey(listener)) { throw new AssertionError( "This LocationListener is already in use."); } if (request == null) { /* * This listener wants to be triggered on EVERY position update, but * it does not want to request position updates. */ if (!listeners.contains(listener)) { listeners.add(listener); } } else { /* * Listener has its own request timing. */ LocationRequestImpl req = (LocationRequestImpl) request; openRequests.put(listener, req); req.immunizeAndStart(listener); } } @Override public void removeLocationUpdates(LocationListener listener) { listeners.remove(listener); LocationRequestImpl impl = openRequests.remove(listener); if (impl != null) { impl.cancel(listener); } } @Override public LocationRequest getLocationRequest() { return new LocationRequestImpl(getHost(), this); } /* * Methods for the Graph Interface */ /** * Graph views: static, as we use global knowledge and maintain one shared * graph (potentially with partitions!) */ private final static LinkedHashMap graphViews = new LinkedHashMap<>(); @Override public TopologyID getTopologyID(NetInterfaceName netName, boolean onlyOnline) { TopologyID id = TopologyID.getIdentifier( netName.toString() + (onlyOnline ? "-online" : "-all"), DefaultTopologyComponent.class); if (!this.graphViews.containsKey(id)) { this.graphViews.put(id, new LocalGraphView(netName, onlyOnline, topology)); } return id; } @Override public TopologyID getTopologyID(NetInterfaceName netName, boolean onlyOnline, double range) { TopologyID id = TopologyID.getIdentifier( netName.toString() + (onlyOnline ? "-online" : "-all") + String.valueOf(range), DefaultTopologyComponent.class); if (!this.graphViews.containsKey(id)) { this.graphViews.put(id, new LocalGraphView(netName, onlyOnline, range, topology)); } return id; } @Override public INode getNode(TopologyID identifier) { assert graphViews.containsKey(identifier); return graphViews.get(identifier).getOwnNode(host); } @Override public Set getNeighbors(TopologyID topologyIdentifier) { assert graphViews.containsKey(topologyIdentifier); return graphViews.get(topologyIdentifier).getNeighbors(host); } @Override public Graph getLocalView(TopologyID topologyIdentifier) { assert graphViews.containsKey(topologyIdentifier); return graphViews.get(topologyIdentifier).getLocalView(); } @Override public Iterable getTopologyIdentifiers() { return graphViews.keySet(); } @Override public String toString() { return "Topology Component #" + getHost().getId() + " at pos " + position.toString(); } }