/*
* 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.views;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import de.tud.kom.p2psim.api.common.HostProperties;
import de.tud.kom.p2psim.api.linklayer.mac.Link;
import de.tud.kom.p2psim.api.linklayer.mac.MacAddress;
import de.tud.kom.p2psim.api.linklayer.mac.MacLayer;
import de.tud.kom.p2psim.api.linklayer.mac.PhyType;
import de.tud.kom.p2psim.api.topology.obstacles.ObstacleModel;
import de.tud.kom.p2psim.api.topology.waypoints.WaypointModel;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.views.FiveGTopologyView.CellLink;
import de.tud.kom.p2psim.impl.topology.views.fiveg.FiveGTopologyDatabase;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
import edu.emory.mathcs.backport.java.util.Arrays;
/**
* This topology view offers a topology for mobile apps - mobile clients
* maintain one to one connections to one or multiple cloud servers or cloudlet
* instances. This view abstracts from real antennas in that the actual range of
* an antenna etc. is just modeled as a property of the link between mobile
* client and the endpoint (cloud/cloudlet) based on a client's position. This
* way, measurements such as the ones by Kaup et al. can be easily incorporated.
*
* TODO add a property to enable usage of access points (lower latency, higher
* BW at certain client positions around the configured positions of APs)
*
. NO, just make this
* configurable via the topology view properties (e.g., a percentage of nodes
* can use such APs) and THEN set the corresponding host property --> if overlay
* code wants to access this information, we might need to add
* {@link HostProperties} to the Simonstrator API.
*
* TODO add distinction for cloudlets and cloud (assuming that cloudlets exhibit
* lower latency), ideally with yet another (TM) host property on the base
* station side:
. NO, again just
* use the groupID of a host as a config setting for this view: e.g., all
* specified groupIDs are Backend hosts vs. direct cloudlets.
*
* FIXME OR: just base this configuration options on the group-ID in the host
* builder?
*
* @author Bjoern Richerzhagen
* @version 1.0, Nov 4, 2015
*/
public class FiveGTopologyView extends AbstractTopologyView {
private Set cloudlets = new LinkedHashSet<>();
private Set clouds = new LinkedHashSet<>();
private Set mobileClients = new LinkedHashSet<>();
private List mobileClientsList = new LinkedList<>();
private List cloudsAndCloudletsList = new LinkedList<>();
private FiveGTopologyDatabase database = null;
/**
* Configuration setting: all group IDs of nodes that act as cloudlets
* (e.g., act as basestations with a lower delay, whatever that means w.r.t.
* the specified model)
*/
private Set groupIDsCloudlet = new LinkedHashSet<>();
/**
* Configuration setting: all group IDs that act as cloud (e.g., backend
* servers). Here, the full latency of a connection from a mobile client to
* a network sever somewhere in the Internet is assumed (e.g., as measured
* by Android end user devices)
*/
private Set groupIDsCloud = new LinkedHashSet<>();
/**
*
* @param phy
*/
public FiveGTopologyView(PhyType phy) {
super(phy, true);
}
@XMLConfigurableConstructor({ "phy" })
public FiveGTopologyView(String phy) {
// UMTS is reset with custom type next.
this(PhyType.UMTS);
setPhy(phy);
}
@Override
public Link getBestNextLink(MacAddress source, MacAddress lastHop,
MacAddress currentHop, MacAddress destination) {
return getLinkBetween(source, destination);
}
@Override
public void changedWaypointModel(WaypointModel model) {
// I don't care, I love it.
}
@Override
public void changedObstacleModel(ObstacleModel model) {
// I don't care, I love it.
}
@Override
protected void addedMac(MacLayer mac) {
String groupId = mac.getHost().getProperties().getGroupID();
if (groupIDsCloud.contains(groupId)) {
clouds.add(mac.getMacAddress());
cloudsAndCloudletsList.add(mac.getMacAddress());
} else if (groupIDsCloudlet.contains(groupId)) {
cloudlets.add(mac.getMacAddress());
cloudsAndCloudletsList.add(mac.getMacAddress());
} else {
mobileClients.add(mac.getMacAddress());
mobileClientsList.add(mac.getMacAddress());
}
}
@Override
protected void updateOutdatedLink(CellLink link) {
if (link.isInvalidLink()) {
// cloud <-> cloud or client <-> client link
return;
}
PositionVector pos = getCachedPosition(link.getMobileClient());
int segId = database.getSegmentID(pos.getX(), pos.getY());
if (segId != link.getSegmentId()) {
// update link data
link.setLinkData(database.getEntryFor(segId, link.isCloudlet()));
}
}
@Override
protected CellLink createLink(MacAddress source,
MacAddress destination) {
boolean sourceIsClient = mobileClients.contains(source);
boolean destinationIsClient = mobileClients.contains(destination);
if (sourceIsClient == destinationIsClient) {
// both client or both not client -> not connected
return new CellLink(source, destination);
}
MacAddress mobileClient = sourceIsClient ? source : destination;
CellLink link = new CellLink(source, destination, true,
getPhyType().getDefaultMTU(), mobileClient,
cloudlets.contains(mobileClient));
updateOutdatedLink(link);
return link;
}
@Override
protected List updateNeighborhood(MacAddress source) {
if (cloudlets.contains(source) || clouds.contains(source)) {
return mobileClientsList;
} else {
assert mobileClients.contains(source);
// Is a client, has all clouds and cloudlets as neighbors
return cloudsAndCloudletsList;
}
}
/*
* Configuration options
*/
/**
* GroupIDs (as specified in the host builder section) that should act as
* clouds (e.g., full measured latency and bandwidth is applied)
*
* @param cloudGroupIDs
*/
@SuppressWarnings("unchecked")
public void setCloudGroups(String[] cloudGroupIDs) {
this.groupIDsCloud = new LinkedHashSet<>(Arrays.asList(cloudGroupIDs));
}
/**
* GroupIDs that act as cloudlets (e.g., lower latency, higher BW) - models
* regional computations facilities.
*
* @param cloudletGroups
*/
@SuppressWarnings("unchecked")
public void setCloudletGroups(String[] cloudletGroups) {
this.groupIDsCloudlet = new LinkedHashSet<>(
Arrays.asList(cloudletGroups));
}
/**
* Set the measurement database providing link quality data for clients
* based on their position.
*
* @param database
*/
public void setDatabase(FiveGTopologyDatabase database) {
assert this.database == null;
this.database = database;
}
/**
* A custom link object supporting dynamic updates of the properties without
* relying on a movement model notification - the client's position is used
* to determine the link performance.
*
* @author Bjoern Richerzhagen
* @version 1.0, Nov 4, 2015
*/
public class CellLink extends DefaultLink {
/**
* Address of the mobile client
*/
private final MacAddress mobileClient;
private FiveGTopologyDatabase.Entry linkData;
private final boolean isUpload;
private final boolean isCloudlet;
private final boolean isInvalidLink;
/**
* An unconnected link
*
* @param source
* @param destination
*/
public CellLink(MacAddress source, MacAddress destination) {
super(source, destination, false, -1, -1, -1, -1);
this.mobileClient = null;
this.isUpload = false;
this.isCloudlet = false;
this.isInvalidLink = true;
}
public CellLink(MacAddress source, MacAddress destination,
boolean isConnected, int mtu, MacAddress mobileClient,
boolean isCloudlet) {
super(source, destination, isConnected, -1, -1, -1, mtu);
this.mobileClient = mobileClient;
this.isCloudlet = isCloudlet;
if (mobileClient.equals(source)) {
isUpload = true;
} else {
assert mobileClient.equals(destination);
isUpload = false;
}
this.isInvalidLink = false;
}
public boolean isInvalidLink() {
return isInvalidLink;
}
public int getSegmentId() {
return linkData == null ? -1 : linkData.getSegmentID();
}
public void setLinkData(FiveGTopologyDatabase.Entry linkData) {
this.linkData = linkData;
}
public MacAddress getMobileClient() {
return mobileClient;
}
public boolean isCloudlet() {
return isCloudlet;
}
@Override
public long getBandwidth(boolean isBroadcast) {
return linkData.getBandwidth(isUpload);
}
@Override
public double getDropProbability() {
return linkData.getDropProbability(isUpload);
}
@Override
public long getLatency() {
return linkData.getLatency(isUpload);
}
}
}