/*
* 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
* @version 1.0, 6 Sep 2018
*/
public abstract class AbstractTopologyComponent implements TopologyComponent {
protected SimHost host;
protected final PositionVector position;
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) {
position.set(location);
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 "TopoComp: " + getHost().getId() + " at " + position.toString();
}
}