Commit 24a5a4c6 authored by Björn Richerzhagen's avatar Björn Richerzhagen
Browse files

Merge remote-tracking branch 'origin/br/sis-development'

parents c0409a4a 6648810b
......@@ -20,10 +20,10 @@
package de.tudarmstadt.maki.simonstrator.api.common.graph;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import de.tudarmstadt.maki.simonstrator.api.Graphs;
......@@ -36,92 +36,124 @@ import de.tudarmstadt.maki.simonstrator.api.Graphs;
*/
public class BasicGraph implements Graph {
private Set<DirectedEdge> edges;
private final Set<IEdge> edges = new LinkedHashSet<>();
private Set<Node> nodes;
private final Set<INode> nodes = new LinkedHashSet<>();
private Map<INodeID, INode> nodesById = new LinkedHashMap<>();
/**
* Creates an empty graph. Components should create new graphs by using the
* {@link Graphs} class in the api.
*/
public BasicGraph() {
edges = new LinkedHashSet<>();
nodes = new LinkedHashSet<>();
//
}
/**
*
* @param nodes
* The set of nodes contained in the graph.
* @param edges
* Set of edges contained in the graph. Assumes that every start
* and end node in the edges is also contained in the nodes set
*/
public BasicGraph(Set<Node> nodes, Set<DirectedEdge> edges) {
this.edges = edges;
this.nodes = nodes;
@Override
public IEdge createEdge(INodeID from, INodeID to) {
IEdge edge = getEdge(from, to);
return (edge == null ? new DirectedEdge(from, to) : edge);
}
assert checkGraphConsistency();
@Override
public IEdge createEdge(INodeID from, INodeID to, double weight) {
IEdge edge = createEdge(from, to);
if (edge == null) {
return new DirectedEdge(from, to, weight);
} else {
edge.setProperty(DirectedEdge.WEIGHT, weight);
return edge;
}
}
/**
* Creates a graph from the given nodes and edges.
*
* Duplicate nodes and edges will be ignored
*/
public BasicGraph(Collection<Node> nodes, Collection<DirectedEdge> edges) {
this(new LinkedHashSet<Node>(nodes), new LinkedHashSet<DirectedEdge>(
edges));
@Override
public INode createNode(INodeID id) {
INode node = getNode(id);
return node != null ? node : new Node(id);
}
/**
* Creates an edge-induced graph.
*
* The nodes are derived from the edges.
*
* @param edges
* the edges of the graph
*/
public BasicGraph(Collection<DirectedEdge> edges) {
this(collectEndnodes(edges), edges);
@Override
public boolean addElement(IElement element) {
if (element instanceof INode) {
INode node = (INode) element;
if (nodes.add(node)) {
// new node
nodesById.put(node.getId(), node);
return true;
}
return false;
} else if (element instanceof IEdge) {
IEdge edge = (IEdge) element;
if (edges.add(edge)) {
// new edge, nodes needed?
if (getNode(edge.fromId()) == null) {
addElement(createNode(edge.fromId()));
}
if (getNode(edge.toId()) == null) {
addElement(createNode(edge.toId()));
}
return true;
}
return false;
} else {
throw new AssertionError("Unknown graph element type.");
}
}
/**
* Creates an edge-induced graph.
*
* The nodes are derived from the end nodes of the edges.
*
* @param edges
* the edges of the graph
*/
@SafeVarargs
public BasicGraph(DirectedEdge... edges) {
this(Arrays.asList(edges));
@Override
public boolean removeElement(IElement element) {
if (element instanceof INode) {
INode node = (INode) element;
nodesById.remove(node.getId());
if (nodes.remove(node)) {
// deleted orphaned edges
Iterator<IEdge> it = edges.iterator();
while (it.hasNext()) {
IEdge edge = it.next();
if (edge.fromId().equals(node.getId())
|| edge.toId().equals(node.getId())) {
it.remove();
}
}
return true;
}
return false;
} else if (element instanceof IEdge) {
return edges.remove(element);
} else {
throw new AssertionError("Unknown graph element type.");
}
}
@Override
public DirectedEdge createEdge(Node from, Node to) {
return new DirectedEdge(from, to);
public Set<INode> getNodes() {
return nodes;
}
@Override
public DirectedEdge createEdge(Node from, Node to, double weight) {
return new DirectedEdge(from, to, weight);
public Set<IEdge> getEdges() {
return this.edges;
}
@Override
public Node createNode(Object id) {
return new Node(id);
public boolean containsNode(INodeID nodeId) {
return nodesById.containsKey(nodeId);
}
@Override
public Set<Node> getNodes() {
return this.nodes;
public INode getNode(INodeID nodeId) {
return nodesById.get(nodeId);
}
@Override
public Set<DirectedEdge> getEdges() {
return this.edges;
public IEdge getEdge(INodeID from, INodeID to) {
for (IEdge edge : edges) {
if (edge.toId().equals(to) && edge.fromId().equals(from)) {
return edge;
}
}
return null;
}
/**
......@@ -129,7 +161,7 @@ public class BasicGraph implements Graph {
* changes the current graph instead of cloning it.
*/
@Override
public BasicGraph getLocalView(Node node, int k) {
public BasicGraph getLocalView(INodeID node, int k) {
return getLocalView(node, k, false);
}
......@@ -139,26 +171,32 @@ public class BasicGraph implements Graph {
* Graph instance is generated. Elsewise, this Graph instance is modified.
*/
@Override
public BasicGraph getLocalView(Node node, int k, boolean clone) {
public BasicGraph getLocalView(INodeID center, int k, boolean clone) {
BasicGraph g = clone ? this.clone() : this;
// filter nodes
Set<Node> kHopNodes = getNeighbors(node, k, false);
Set<INodeID> kHopNodes = getNeighbors(center, k, false);
// determine edges
Set<DirectedEdge> kHopEdges = new LinkedHashSet<DirectedEdge>();
for (DirectedEdge edge : g.edges) {
if (kHopNodes.contains(edge.getStartNode())
&& kHopNodes.contains(edge.getEndNode())) {
Set<IEdge> kHopEdges = new LinkedHashSet<IEdge>();
for (IEdge edge : g.edges) {
if (kHopNodes.contains(edge.fromId())
&& kHopNodes.contains(edge.toId())) {
kHopEdges.add(edge);
}
}
// modify g accordingly
g.nodes.clear();
g.nodes.addAll(kHopNodes);
g.edges.clear();
g.edges.addAll(kHopEdges);
Iterator<INode> itNodes = g.nodes.iterator();
while (itNodes.hasNext()) {
INode node = itNodes.next();
if (!kHopNodes.contains(node.getId())) {
itNodes.remove();
g.nodesById.remove(node.getId());
}
}
g.edges.retainAll(kHopEdges);
assert checkGraphConsistency();
......@@ -173,9 +211,10 @@ public class BasicGraph implements Graph {
* for the neighborhood
*/
@Override
public Set<Node> getNeighbors(Node node, int k, boolean directedNeighborhood) {
return getNeighbors(node, k, directedNeighborhood,
new LinkedHashSet<Node>());
public Set<INodeID> getNeighbors(INodeID center, int k,
boolean directedNeighborhood) {
return getNeighbors(center, k, directedNeighborhood,
new LinkedHashSet<INodeID>());
}
/**
......@@ -183,9 +222,9 @@ public class BasicGraph implements Graph {
* the nodes set
*/
private boolean checkGraphConsistency() {
for (DirectedEdge directedEdge : edges) {
if (!nodes.contains(directedEdge.getStartNode())
|| !nodes.contains(directedEdge.getEndNode())) {
for (IEdge directedEdge : edges) {
if (!nodesById.containsKey(directedEdge.fromId())
|| !nodesById.containsKey(directedEdge.toId())) {
return false;
}
}
......@@ -193,37 +232,25 @@ public class BasicGraph implements Graph {
return true;
}
/**
* Returns the set of start and end nodes of the given set of edges
*/
private static Set<Node> collectEndnodes(Iterable<DirectedEdge> edges) {
final Set<Node> nodes = new HashSet<>();
for (final DirectedEdge edge : edges) {
nodes.add(edge.getStartNode());
nodes.add(edge.getEndNode());
}
return nodes;
}
// helper method
private Set<Node> getNeighbors(Node node, int k,
boolean directedNeighborhood, LinkedHashSet<Node> visited) {
private Set<INodeID> getNeighbors(INodeID node, int k,
boolean directedNeighborhood, LinkedHashSet<INodeID> visited) {
assert k >= 0;
if (k == 0) {
visited.add(node);
LinkedHashSet<Node> oneNodeNeighborSet = new LinkedHashSet<Node>();
LinkedHashSet<INodeID> oneNodeNeighborSet = new LinkedHashSet<INodeID>();
oneNodeNeighborSet.add(node);
return oneNodeNeighborSet;
}
visited.add(node);
LinkedHashSet<Node> neighbors = new LinkedHashSet<Node>();
LinkedHashSet<INodeID> neighbors = new LinkedHashSet<INodeID>();
neighbors.add(node);
for (Node neighbor : getNeighbors(node, directedNeighborhood)) {
for (INodeID neighbor : getNeighbors(node, directedNeighborhood)) {
if (!visited.contains(neighbor))
neighbors.addAll(getNeighbors(neighbor, k - 1,
directedNeighborhood, visited));
......@@ -241,13 +268,14 @@ public class BasicGraph implements Graph {
* @return
*/
@Override
public Set<DirectedEdge> getOutgoingEdges(Node node) {
assert this.nodes.contains(node);
public Set<IEdge> getOutgoingEdges(INodeID node) {
assert getNode(node) != null;
Set<DirectedEdge> outgoingEdges = new LinkedHashSet<DirectedEdge>();
for (DirectedEdge directedEdge : this.edges) {
if (directedEdge.getStartNode().equals(node))
Set<IEdge> outgoingEdges = new LinkedHashSet<IEdge>();
for (IEdge directedEdge : this.edges) {
if (directedEdge.fromId().equals(node)) {
outgoingEdges.add(directedEdge);
}
}
return outgoingEdges;
}
......@@ -261,13 +289,14 @@ public class BasicGraph implements Graph {
* @return
*/
@Override
public Set<DirectedEdge> getIncomingEdges(Node node) {
assert this.nodes.contains(node);
public Set<IEdge> getIncomingEdges(INodeID node) {
assert getNode(node) != null;
Set<DirectedEdge> incomingEdges = new LinkedHashSet<DirectedEdge>();
for (DirectedEdge directedEdge : this.edges) {
if (directedEdge.getEndNode().equals(node))
Set<IEdge> incomingEdges = new LinkedHashSet<IEdge>();
for (IEdge directedEdge : this.edges) {
if (directedEdge.toId().equals(node)) {
incomingEdges.add(directedEdge);
}
}
return incomingEdges;
}
......@@ -280,14 +309,14 @@ public class BasicGraph implements Graph {
*
*/
@Override
public Set<Node> getNeighbors(Node node, boolean directedNeighborhood) {
Set<Node> neighbors = new LinkedHashSet<Node>();
for (DirectedEdge edge : edges) {
if (edge.getStartNode().equals(node))
neighbors.add(edge.getEndNode());
else if (!directedNeighborhood && edge.getEndNode().equals(node))
neighbors.add(edge.getStartNode());
public Set<INodeID> getNeighbors(INodeID node, boolean directedNeighborhood) {
Set<INodeID> neighbors = new LinkedHashSet<INodeID>();
for (IEdge edge : edges) {
if (edge.fromId().equals(node)) {
neighbors.add(edge.toId());
} else if (!directedNeighborhood && edge.toId().equals(node)) {
neighbors.add(edge.fromId());
}
}
return neighbors;
}
......@@ -299,195 +328,24 @@ public class BasicGraph implements Graph {
* @see #getNeighbors(Node, int, boolean)
*/
@Override
public Set<Node> getNeighbors(Node node) {
public Set<INodeID> getNeighbors(INodeID node) {
return getNeighbors(node, true);
}
@Override
public Set<GraphElement> getAllElements() {
LinkedHashSet<GraphElement> elements = new LinkedHashSet<GraphElement>();
elements.addAll(getNodes());
elements.addAll(getEdges());
return elements;
}
public boolean remove(Node node) {
return this.nodes.remove(node);
}
public boolean remove(DirectedEdge edge) {
return this.edges.remove(edge);
}
@Override
public boolean contains(GraphElement element) {
if (element instanceof Node) {
return getNodes().contains((Node) element);
} else if (element instanceof DirectedEdge) {
return getEdges().contains((DirectedEdge) element);
} else {
throw new IllegalArgumentException("unknown GraphElement type");
}
}
@Override
public Graph add(GraphElement element) {
if (element instanceof Node) {
nodes.add((Node) element);
} else if (element instanceof DirectedEdge) {
edges.add((DirectedEdge) element);
} else {
throw new IllegalArgumentException("unknown GraphElement type");
}
return this;
}
@Override
public boolean remove(GraphElement element) {
if (element instanceof Node) {
return nodes.remove((Node) element);
} else if (element instanceof DirectedEdge) {
return edges.remove((DirectedEdge) element);
} else {
throw new IllegalArgumentException("unknown GraphElement type");
}
}
@Override
public BasicGraph clone() {
// clone nodes
Set<Node> newNodes = new LinkedHashSet<Node>();
for (Node node : this.nodes) {
Node newNode = node.clone();
newNodes.add(newNode);
/*
* As per the API contract, the inner objects are NOT cloned. This
* cloned graph is just a new view.
*/
BasicGraph g = new BasicGraph();
for (INode node : this.nodes) {
g.addElement(node);
}
// clone edges
Set<DirectedEdge> newEdges = new LinkedHashSet<DirectedEdge>();
for (DirectedEdge directedEdge : this.edges) {
newEdges.add(directedEdge.clone());
for (IEdge directedEdge : this.edges) {
g.addElement(directedEdge);
}
// return result
return new BasicGraph(newNodes, newEdges);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Nodes: ");
sb.append(this.nodes);
sb.append(" Edges: ");
sb.append(this.edges);
return sb.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((edges == null) ? 0 : edges.hashCode());
result = prime * result + ((nodes == null) ? 0 : nodes.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BasicGraph other = (BasicGraph) obj;
if (edges == null) {
if (other.edges != null)
return false;
} else if (!edges.equals(other.edges))
return false;
if (nodes == null) {
if (other.nodes != null)
return false;
} else if (!nodes.equals(other.nodes))
return false;
return true;
}
/**
* The equals() method checks only equality based on the equal method in the
* Node and DirectedEdge implementations. These implementations do not
* compare all attributes. This method compares two graphs based on the
*/
@Override
public boolean equalsAttributes(Graph otherGraph) {
return isContainedInBasedOnEqualAttributes(this.edges,
otherGraph.getEdges())
&& isContainedInBasedOnEqualAttributes(otherGraph.getEdges(),
this.edges)
&& isContainedInBasedOnEqualAttributes(this.nodes,
otherGraph.getNodes())
&& isContainedInBasedOnEqualAttributes(otherGraph.getNodes(),
this.nodes);
}
// returns true if setA is contained in setB based on the
// GraphelElement.equalsAttributes() method
private boolean isContainedInBasedOnEqualAttributes(
Set<? extends GraphElement> setA, Set<? extends GraphElement> setB) {
for (GraphElement elA : setA) {
boolean found = false;
for (GraphElement elB : setB) {
if (elA.equalsAttributes(elB)) {
found = true;
break;
}
}
if (!found)
return false;
}
return true;
}
@Override
public boolean isBidirectional() {
for (DirectedEdge edge : getEdges()) {
boolean found = false;
for (DirectedEdge otherEdge : getEdges()) {
if (edge.getStartNode().equals(otherEdge.getEndNode())
&& edge.getEndNode().equals(otherEdge.getStartNode())) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
@Override
public Graph createAndAddNode(Object id) {
return add(createNode(id));
}
@Override
public Graph createAndAddEdge(Node from, Node to) {
return add(createEdge(from, to));
}
@Override
public Graph createAndAddEdge(Node from, Node to, double weight) {
return add(createEdge(from, to, weight));
return g;
}
}
......@@ -20,106 +20,105 @@
package de.tudarmstadt.maki.simonstrator.api.common.graph;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSType;
/**
* Represents a directed edge in a topology
*
* @author Michael Stein
*/
public class DirectedEdge implements Cloneable, GraphElement {
private static final double NO_WEIGHT_PLACEHOLDER = Double.NaN;
private final Node startNode, endNode;
public class DirectedEdge implements IEdge {
private final String id;
public static final GraphElementProperty<Double> WEIGHT = new GraphElementProperty<>(
"WEIGHT", Double.class);
private final boolean weighted;
private final INodeID startNode, endNode;
private final double weight;
/**
* Node properties (attached objects)
*/
private final Map<SiSType<?>, Object> properties = new LinkedHashMap<>();
/**
* Creates an unweighted, directed edge
*/
public DirectedEdge(Node startNode, Node endNode) {
this(startNode, endNode, false, NO_WEIGHT_PLACEHOLDER, startNode
.toString() + "->" + endNode.toString());
public DirectedEdge(INodeID startNode, INodeID endNode) {
this.startNode = startNode;
this.endNode = endNode;
}
/**
* Creates an weighted, directed edge
*/
public DirectedEdge(Node startNode, Node endNode, double weight) {
this(startNode, endNode, true, weight, startNode.toString() + "->"
+ endNode.toString());
public DirectedEdge(INodeID startNode, INodeID endNode, double weight) {
this(startNode, endNode);
if (!Double.isNaN(weight)) {
this.properties.put(WEIGHT, weight);
}
}
// Generic private constructor
private DirectedEdge(Node startNode, Node endNode, boolean weighted,
double weight, String id) {
this.startNode = startNode;
this.endNode = endNode;
this.weight = weight;
this.weighted = weighted;
this.id = id;
}
public Node getStartNode() {
@Override
public INodeID fromId() {
return startNode;
}
public Node getEndNode() {
@Override
public INodeID toId() {
return endNode;
}
public boolean isWeighted() {
return weighted;
@SuppressWarnings("unchecked")
@Override
public <T> T getProperty(SiSType<T> property) {
return (T) properties.get(property);
}
public double getWeight() {
return weight;
@Override
public <T> IEdge setProperty(SiSType<T> property, T value) {
if (value == null) {
properties.remove(property);
} else {
properties.put(property, value);
}
return this;
}
@Override
public String getId() {
return this.id;
public Map<SiSType<?>, Object> getProperties() {
return Collections.unmodifiableMap(properties);
}
/**
* This is an equals() implementation that check equality of all attributes.
* This method is not used by hash maps etc.
*/
@Override
public boolean equalsAttributes(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DirectedEdge other = (DirectedEdge) obj;
if (endNode == null) {
if (other.endNode != null)
return false;
} else if (!endNode.equals(other.endNode))
return false;
if (startNode == null) {
if (other.startNode != null)
return false;
} else if (!startNode.equals(other.startNode))
return false;
if (Double.doubleToLongBits(weight) != Double
.doubleToLongBits(other.weight))
return false;
if (weighted != other.weighted)
return false;
return true;
public void addPropertiesFrom(IElement other) {
properties.putAll(other.getProperties());
}
@Override
public void clearProperties() {
properties.clear();
}
public boolean isWeighted() {
return properties.containsKey(WEIGHT);
}
public double getWeight() {
return (double) properties.get(WEIGHT);
}
@Override
public String toString() {
return "DirectedEdge [" + (startNode != null ? startNode + " -> " : "")
+ (endNode != null ? endNode : "")
+ (properties != null ? ", properties=" + properties : "")
+ "]";
}
/**
* Be careful: This hashCode() implementation considers only the start node
* and the end node of the edge. Extent this class if you need different
* behavior
*/
@Override
public int hashCode() {
final int prime = 31;
......@@ -130,11 +129,6 @@ public class DirectedEdge implements Cloneable, GraphElement {
return result;
}
/**
* Be careful: This equals() implementation considers only the start node
* and the end node of the edge. Use equalsAttributes for a comparison of
* all attributes or extend this class if you need different behavior
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
......@@ -157,18 +151,4 @@ public class DirectedEdge implements Cloneable, GraphElement {
return true;
}
// TODO this implementation of clone creates new instances of Node, even
// though this is already done in Graph.clone as well. This is still
// expected to work correctly because hashCode() and equals()
// are overridden in Node, but it is quite redundant and consumes memory...
@Override
public DirectedEdge clone() {
return new DirectedEdge(startNode.clone(), endNode.clone(),
weighted, weight, id);
}
@Override
public String toString() {
return this.getId();
}
}
......@@ -31,30 +31,27 @@ import java.util.Set;
*/
public interface Graph extends Cloneable {
/*
* Creator methods
*/
/**
* Create and return a node. The node is <strong>not</strong> yet added to
* the graph. If a node with the given ID is already in the graph, that node
* is returned instead.
* is returned instead and no new instance is created.
*
* @param id
* @return
*/
public Node createNode(Object id);
public INode createNode(INodeID id);
/**
* Create and return an unweighted edge. The edge is <strong>not</strong>
* yet added to the graph. In case the same edge already exists in the
* graph, that edge is returned instead.
* graph, that edge is returned instead and no new instance is created.
*
* @param from
* @param to
* @return
*/
public DirectedEdge createEdge(Node from, Node to);
public IEdge createEdge(INodeID from, INodeID to);
/**
* Create and return a weighted edge. The edge is <strong>not</strong> yet
* added to the graph. In case the same edge already exists in the graph,
......@@ -65,29 +62,96 @@ public interface Graph extends Cloneable {
* @param weight
* weight of the edge
* @return
* @deprecated add weights via the respective {@link IElement} properties.
*/
@Deprecated
public IEdge createEdge(INodeID from, INodeID to, double weight);
/**
* Adds an element ({@link IEdge} or {@link INode}) to the graph. If the
* element is already contained in the graph, the graph remains unchanged.
* If an edge is added and the respective nodes are not present in the
* graph, they are created.
*
* Please note: properties annotated to elements are not considered when
* checking for already present elements.
*
* @param element
* @return false, if the element was already present.
*/
public boolean addElement(IElement element);
/**
* Remove the given {@link IElement} from the graph. In case of nodes, all
* edges referring to the given node are also deleted. Orphaned nodes, e.g.,
* nodes that do not have any edges, are <strong>NOT</strong> removed
* automatically.
*
* @param element
* @return
*/
public boolean removeElement(IElement element);
/**
* True, if the given node is contained in the graph
*
* @param nodeId
* @return
*/
public DirectedEdge createEdge(Node from, Node to, double weight);
public boolean containsNode(INodeID nodeId);
/*
* Graph Interface and convenience methods
*/
public Set<Node> getNodes();
/**
* Returns all edges in the graph
*
* @return
*/
public Set<IEdge> getEdges();
/**
* Returns all nodes in the graph
*
* @return
*/
public Set<INode> getNodes();
/**
* Returns the node with the given ID if existent in the graph. null
* otherwise
*
* @param node
* @return
*/
public INode getNode(INodeID nodeId);
/**
* Returns the edge (if present) between from and to, null otherwise
*
* @param from
* @param to
* @return edge or null
*/
public IEdge getEdge(INodeID from, INodeID to);
public Set<DirectedEdge> getEdges();
/*
* Convenience methods
*/
/**
* Computes subgraph of the currently known local view. This operation
* changes the current graph instead of cloning it.
*/
public BasicGraph getLocalView(Node node, int k);
public Graph getLocalView(INodeID node, int k);
/**
* Computes subgraph of the currently known local view. The clone parameter
* specifies whether this Graph instance is changed. If clone is true, a new
* Graph instance is generated. Elsewise, this Graph instance is modified.
*/
public BasicGraph getLocalView(Node node, int k, boolean clone);
public Graph getLocalView(INodeID node, int k, boolean clone);
/**
* For the given node, compute the outgoing edges in the graph
......@@ -97,7 +161,7 @@ public interface Graph extends Cloneable {
*
* @return
*/
public Set<DirectedEdge> getOutgoingEdges(Node node);
public Set<IEdge> getOutgoingEdges(INodeID node);
/**
* For the given node, compute the incoming edges in the graph
......@@ -107,7 +171,7 @@ public interface Graph extends Cloneable {
*
* @return
*/
public Set<DirectedEdge> getIncomingEdges(Node node);
public Set<IEdge> getIncomingEdges(INodeID node);
/**
* Returns the nodes contained in the k-hop neighborhood of the specified
......@@ -116,7 +180,8 @@ public interface Graph extends Cloneable {
* If the directedNeighborhood flag is true, edge directions are considered
* for the neighborhood
*/
public Set<Node> getNeighbors(Node node, int k, boolean directedNeighborhood);
public Set<INodeID> getNeighbors(INodeID node, int k,
boolean directedNeighborhood);
/**
* returns the strict 1-hop neighbors of the specified node.
......@@ -125,7 +190,7 @@ public interface Graph extends Cloneable {
* for the neighborhood
*
*/
public Set<Node> getNeighbors(Node node, boolean directedNeighborhood);
public Set<INodeID> getNeighbors(INodeID node, boolean directedNeighborhood);
/**
* Returns the strict 1-hop neighbors of the specified node, considering
......@@ -133,73 +198,17 @@ public interface Graph extends Cloneable {
*
* @see #getNeighbors(Node, int, boolean)
*/
public Set<Node> getNeighbors(Node node);
public Set<GraphElement> getAllElements();
/**
*
* TODO define the method's contract
*
* @param element
* @return the graph object for chaining.
*/
public Graph add(GraphElement element);
public Set<INodeID> getNeighbors(INodeID node);
/**
* Creates and adds the node with the given ID to the graph. If the node is
* already present in the graph, the graph remains unchanged
*
* @param id
* @return
*/
public Graph createAndAddNode(Object id);
public Graph createAndAddEdge(Node from, Node to);
public Graph createAndAddEdge(Node from, Node to, double weight);
/**
* TODO define the method's contract w.r.t. duplicates etc.
*
* @param element
* @return
*/
public boolean remove(GraphElement element);
/**
* TODO define the method's contract w.r.t. duplicates etc.
*
* @param element
* @return
*/
public boolean contains(GraphElement element);
/**
* Enforce cloning
* Clones the graph (returns a new view that can be modified). Please note:
* the underlying objects (nodes, edges) are <strong>NOT</strong> cloned!
* Reason behind that: {@link Graph} contains the structure of nodes and
* edges (potentially a subview on a network), while nodes and edges within
* these subviews remain immutable.
*
* @return
*/
public Graph clone();
/**
* The equals() method checks only equality based on the equal method in the
* Node and DirectedEdge implementations. These implementations do not
* compare all attributes. This method compares two graphs based on the
*
* @deprecated should this be part of the general interface?
*/
public boolean equalsAttributes(Graph otherGraph);
/**
* Returns true if for each directed edge there exists an edge into the
* reverse direction (does not consider edge weight or other attributes)
*
* FIXME really slow. was only implemented for debugging purposes and could
* be done better for sure... :)
*
* @deprecated should this be part of the general interface?
*/
public boolean isBidirectional();
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.common.graph;
import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSType;
/**
* Graph element property. In most cases you should be able to use the available
* {@link SiSType}s. If no matching type is registered, or you need custom
* properties, just create an instance of this class. The resulting
* {@link SiSType} is <strong>NOT</strong> added to the global SiS namespace
* (SiSTypes).
*
* @author Bjoern Richerzhagen
*
*/
public class GraphElementProperty<T> extends SiSType<T> {
public GraphElementProperty(String name, Class<T> valueType) {
/*
* To avoid collisions, a name prefix is added.
*/
super("GraphElementProperty-" + name, valueType, null);
}
}
/*
* Copyright (c) 2005-2010 KOM Multimedia Communications Lab
* Copyright (c) 2005-2010 KOM Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
* This file is part of Simonstrator.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* Simonstrator.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.
......@@ -20,29 +20,31 @@
package de.tudarmstadt.maki.simonstrator.api.common.graph;
import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSType;
/**
* Mainly serves as a marker interface
* Minimal Edge Interface as used in the SiS. Edges can be annotated with
* {@link SiSType}s. They are immutable within one specific graph-context
* (determined by the graph-object they were created within).
*
* @author michael.stein
* @version 1.0, 12.12.2014
* @author Bjoern Richerzhagen
*
*/
public interface GraphElement {
public interface IEdge extends IElement {
/**
* Returns the id of this element.
* {@link INodeID} of the source node
*
* TODO is object a good idea in this context?
*
* @return the unique identifier of this element
* @return
*/
Object getId();
public INodeID fromId();
/**
* All graph elements provide a method that compares all attributes directly
* in order to determine if they are totally equal. This is required as the
* equals() implementation of Node and DirectedEdge compares only
* identifiers.
* {@link INodeID} of the destination node
*
* @return
*/
public boolean equalsAttributes(Object otherObj);
public INodeID toId();
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.common.graph;
import java.util.Map;
import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSType;
/**
* Common base interface for an element in the graph
*
* @author Bjoern Richerzhagen
*
*/
public interface IElement {
/**
* Get the value associated with the given property at this graph element.
* Null, if the property was not set.
*
* @param property
* @return
*/
public <T> T getProperty(SiSType<T> property);
/**
* Set (or overwrite) a property with the provided value. If the value ===
* null, the property is removed.
*
* @param property
* @param value
* @return self for chaining
*/
public <T> IElement setProperty(SiSType<T> property, T value);
/**
* Returns all {@link SiSType}s that are annotated to the graph element
*
* @return
*/
public Map<SiSType<?>, Object> getProperties();
/**
* Adds the properties from the other {@link IElement} to our current
* properties. If a property already exists locally, its value is replaced
* by the other value.
*
* @param other
*/
public void addPropertiesFrom(IElement other);
/**
* Deletes all associated properties from this IElement
*/
public void clearProperties();
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.common.graph;
import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSType;
/**
* Basic node interface, as used by the SiS. Nodes can be annotated with
* {@link SiSType}s. They are immutable within one specific graph-context
* (determined by the graph-object they were created within).
*
* @author Bjoern Richerzhagen
*
*/
public interface INode extends IElement {
/**
* {@link INodeID} of the node.
*
* @return
*/
public INodeID getId();
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.common.graph;
import java.util.LinkedHashMap;
import java.util.Map;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
/**
* As the SiS and Monitoring deal with multiple topologies collected in the
* underlay, any overlay and the applications, we need a common identifier for
* nodes. Seems that the NetID is suited for most practical scenarios. This
* class provides static methods to retrieve the ID.
*
* In cases, where a NetID is not known or not needed (e.g., in graph utils),
* there is also a get-method that is based on strings. This, however, should
* not be used in production overlay code.
*
* @author Bjoern Richerzhagen
*
*/
public class INodeID {
public final NetID netId;
private final static Map<NetID, INodeID> ids = new LinkedHashMap<>();
/**
* Retrieve the {@link INodeID} for the given {@link NetID}.
*
* @param netId
* @return
*/
public static INodeID get(NetID netId) {
INodeID id = ids.get(netId);
if (id == null) {
id = new INodeID(netId);
ids.put(netId, id);
}
return id;
}
/**
*
* @param identifier
* @return
* @deprecated This should not be used in production code.
*/
@Deprecated
public static INodeID get(String identifier) {
NetID netId = new DummyNetID(identifier);
return get(netId);
}
private INodeID(NetID netId) {
this.netId = netId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((netId == null) ? 0 : netId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
INodeID other = (INodeID) obj;
if (netId == null) {
if (other.netId != null)
return false;
} else if (!netId.equals(other.netId))
return false;
return true;
}
@Override
public String toString() {
return netId.toString();
}
/**
* A dummy NetID used internally, if the String-based identifiers are used
* instead of the {@link NetID}-based IDs.
*
* @author Bjoern Richerzhagen
*
*/
private static class DummyNetID implements NetID {
private static final long serialVersionUID = 1L;
private final String id;
public DummyNetID(String id) {
this.id = id;
}
@Override
public int getTransmissionSize() {
return 4;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DummyNetID other = (DummyNetID) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
@Override
public String toString() {
return id;
}
}
}
......@@ -20,85 +20,82 @@
package de.tudarmstadt.maki.simonstrator.api.common.graph;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSType;
/**
* Represents a node in a topology
*
* FIXME (BR): are the attached objects really needed?
* Represents a node in a topology. Nodes are equal, if their ID is equal
* (usually a plain net-ID). The attached properties are not considered for
* equality and have to be merged or replaced based on the desired semantics.
*
* @author michael.stein
*/
public class Node implements Cloneable, GraphElement {
public class Node implements INode {
/**
* The node identifier. Has to be unique.
*/
protected final Object id;
protected final INodeID id;
/**
* FIXME (BR) is this really needed?
* Node properties (attached objects)
*/
protected Object obj;
private final Map<SiSType<?>, Object> properties = new LinkedHashMap<>();
public Node(Object obj, Object id) {
this.obj = obj;
this.id = id;
}
/**
* @param id
* unique node identifier
*/
public Node(Object id) {
this.obj = null;
public Node(INodeID id) {
this.id = id;
}
/**
* @return the attached object
*/
public Object getObj() {
return obj;
@Override
public INodeID getId() {
return id;
}
/**
* Attaches an object to this Node
*
* @param obj
* the attached object
*/
public void setObj(Object obj) {
this.obj = obj;
@SuppressWarnings("unchecked")
@Override
public <T> T getProperty(SiSType<T> property) {
return (T) properties.get(property);
}
@Override
public Object getId() {
return id;
public <T> INode setProperty(SiSType<T> property, T value) {
if (value == null) {
properties.remove(property);
} else {
properties.put(property, value);
}
return this;
}
@Override
public Map<SiSType<?>, Object> getProperties() {
return Collections.unmodifiableMap(properties);
}
/**
* This is an equals() implementation that check equality of all attributes. This method is not used by hash maps etc.
*/
@Override
public boolean equalsAttributes(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
public void addPropertiesFrom(IElement other) {
properties.putAll(other.getProperties());
}
/**
* Be careful: This hashCode() implementation considers only the node identifier. Extend this class if you need different behavior
*/
@Override
public void clearProperties() {
properties.clear();
}
@Override
public String toString() {
return "Node [" + (id != null ? "id=" + id + ", " : "")
+ (properties != null ? "properties=" + properties : "") + "]";
}
@Override
public int hashCode() {
final int prime = 31;
......@@ -107,9 +104,6 @@ public class Node implements Cloneable, GraphElement {
return result;
}
/**
* Be careful: This equals() implementation considers only the node idetnifier. Use equalsAttributes for a comparison of all attributes or extend this class if you need different behavior
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
......@@ -127,18 +121,4 @@ public class Node implements Cloneable, GraphElement {
return true;
}
/**
* This clone method creates a new Node object, but uses the same instance
* for id and obj! Override this method if you need different behavior
*/
@Override
public Node clone() {
return new Node(obj, id);
}
@Override
public String toString() {
return String.valueOf(getId());
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.component.overlay;
import de.tudarmstadt.maki.simonstrator.api.common.Transmitable;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
import de.tudarmstadt.maki.simonstrator.api.component.transport.TransInfo;
/**
* API-interface for OverlayContacts (does not include UniqueIDs, as these might
* not be required for all types of overlays).
*
* @author Bjoern Richerzhagen
*
*/
public interface IOverlayContact extends Transmitable {
/**
* Returns the TransportAddress of a particular OverlayAgent
*
* @return the TransportAddress of a particular OverlayAgent
*/
@Deprecated
public TransInfo getTransInfo();
/**
* Returns the NetID of an overlay node
*
* @return
*/
public NetID getNetID();
}
......@@ -70,9 +70,19 @@ public interface OverlayComponent extends HostComponent {
* Returns the Overlay-ID of the node in the current overlay
*
* @return
*
* @deprecated use the {@link IOverlayContact} instead!
*/
@Deprecated
public UniqueID getNodeID();
/**
* Returns the local overlay contact of the current component.
*
* @return
*/
public IOverlayContact getLocalOverlayContact();
/**
* This listener is informed if the peer status changes
*
......
# The System Information Service
TODO documentation
\ No newline at end of file
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.component.sis;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.HostComponent;
/**
* This component provides the service interface for the SiS (System Information
* Service), acting as a proxy to resolve information. Internally, the SiS uses
* local storage as well as the monitoring component to answer data requests.
* This interface is to be used by components that want to access the SiS to (i)
* access information from other components or the network, or (ii) provide
* information to other components or the network.
*
* Bringing providers and consumers together is then an integral part of the
* SiS's internal logic.
*
* The intentions and the contracts of this component are based on a proposal in
* the MAKI-Seminar (see Synology for slideset).
*
* @author Bjoern Richerzhagen
*
*/
public interface SiSComponent extends HostComponent {
/**
* Enables components to provide information (once or periodically or based
* on events) using the {@link SiSInformationProvider} interface of the SiS.
* For most methods, you need to create a {@link SiSRequest} first, using
* the createRequestFor-method of the SiS.
*
* @return
*/
public SiSInformationProvider provide();
/**
* Access to information in the SiS. The complex logic is hidden behind the
* {@link SiSInformationConsumer} interface. For most methods, you need to
* create a {@link SiSRequest} first, using the createRequestFor-method of
* the SiS.
*
* @return
*/
public SiSInformationConsumer get();
/**
* For more complex requests and provider interactions, you might need to
* describe your information. Use the {@link SiSInfoPropertiesFactory} to
* achieve this task.
*
* @return
*/
public SiSInfoPropertiesFactory describe();
/**
* Use this method to test whether the provided {@link INodeID} corresponds
* to our own local node. If nodeID == null, this has to return true!
*
* @param nodeID
* @return
*/
public boolean isLocalNode(INodeID nodeID);
/**
* A node might have multiple nodeIDs associated. This method is guaranteed
* to return one of those. Which one, is not specified.
*
* @return
*/
public INodeID getLocalNodeId();
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.component.sis;
import de.tudarmstadt.maki.simonstrator.api.component.sis.SiSInformationProvider.SiSProviderHandle;
import de.tudarmstadt.maki.simonstrator.api.component.sis.exception.InformationNotAvailableException;
/**
* Callback provided by the DataProvider that is then queried for the actual
* data if the SiS needs it. If the data is (currently) not available, throw an
* {@link InformationNotAvailableException} exception. This does
* <strong>not</strong> remove the source. Instead, use revoke to tell the SiS
* that you do no longer provide information.
*
* @author Bjoern Richerzhagen
*
* @param <T>
* result type
*/
public interface SiSDataCallback<T> {
/**
* Return the current value
*
* @param providerHandle
* can be used to revoke access to the provider
* @return
*/
public T getValue(SiSProviderHandle providerHandle)
throws InformationNotAvailableException;
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.component.sis;
/**
* A description object that characterizes a given information in the SiS. This
* is utilized for both: descriptions as well as requests of data (e.g., the
* {@link SiSRequest} extends this interface). Both share common
* QoS-characteristics modeled in this interface.
*
* The interface supports chaining.
*
* Remember to alter the clone() method, when adding new properties!
*
* @author Bjoern Richerzhagen
*
*/
public class SiSInfoProperties implements Cloneable {
/**
* "null" properties.
*/
public static final SiSInfoProperties NONE = new SiSInfoProperties();
private SiSScope scope = null;
private Class<?> sourceComponent = null;
/*
* Here, we should collect some ideas for common description properties.
*/
/*
* TODO cost to get this information OR cost we are willing to spend
*/
/*
* TODO accuracy of the information
*/
/**
* Later, we might want to define scopes in a more flexible way?
*
* @author Bjoern Richerzhagen
*
*/
public enum SiSScope {
NODE_LOCAL, REGIONAL, GLOBAL
}
/**
* Set the scope of the respective information
*
* @param scope
* @return
*/
public SiSInfoProperties setScope(SiSScope scope) {
this.scope = scope;
return this;
}
/**
* Scope of this request
*
* @return scope or null
*/
public SiSScope getScope() {
return scope;
}
/**
* Optional filter based on the source component(s) of the data (e.g., only
* Bypass-Data). This is NOT limited to HostComponents.
*
* @param component
* interface of the (desired) source component. This supports
* type inheritance - if you specify e.g., PubSubComponent, you
* will get data from any source extending that interface, so
* from BypassPubSubComponent for example.
*
* @return reference to the current properties instance to support chaining
*/
public <T> SiSInfoProperties setSourceComponent(
Class<T> sourceComponent) {
this.sourceComponent = sourceComponent;
return this;
}
/**
* Source component of this information
*
* @return source component or null
*/
public Class<?> getSourceComponent() {
return sourceComponent;
}
@Override
public SiSInfoProperties clone() {
SiSInfoProperties prop = new SiSInfoProperties();
prop.setScope(scope);
prop.setSourceComponent(sourceComponent);
return prop;
}
@Override
public String toString() {
return "SiSInfoProperties ["
+ (scope != null ? "scope=" + scope + ", " : "")
+ (sourceComponent != null ? "sourceComponent="
+ sourceComponent : "") + "]";
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.component.sis;
import de.tudarmstadt.maki.simonstrator.api.component.sis.SiSInfoProperties.SiSScope;
/**
* Convenience class that aids in creating {@link SiSInfoProperties} objects for
* a number of common scenarios
*
* @author Bjoern Richerzhagen
*
*/
public class SiSInfoPropertiesFactory {
/**
* {@link SiSInfoProperties} for local data from a given source
*
* @return
*/
public <T> SiSInfoProperties localDataFrom(
Class<T> source) {
SiSInfoProperties prop = new SiSInfoProperties();
prop.setSourceComponent(source).setScope(SiSScope.NODE_LOCAL);
return prop;
}
public SiSInfoProperties globalView() {
SiSInfoProperties prop = new SiSInfoProperties();
prop.setScope(SiSScope.GLOBAL);
return prop;
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.component.sis;
import java.util.Map;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.sis.exception.InformationNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSType;
/**
* Consumer interface, i.e., interface used to access information from the SiS.
* Complex request patterns are modeled using {@link SiSRequest}s. In general we
* distinguish between <i>local state</i> and <i>observations</i>.
*
* <i>Local state</i> is associated to our own node (e.g., a buffer length or a
* battery level) and can be retrieved from one or more of the currently running
* mechanisms on that node (without using monitoring). If the value cannot be
* directly retrieved, it may be derived from another state value. As these
* operations involve only the local node, the result is returned directly.
*
* <i>Observations</i> denote state of other nodes in the network. An
* observation might, for example, be the RTT to another node, or the average
* RTT in the current subnet. Usually, some observations are kept locally (e.g.,
* the RTT to direct neighbors), whereas others might need to be fetched by the
* monitoring system (e.g., the average RTT in the whole subnet). Therefore, two
* differnet access method types exist in this interface: local observations can
* be retrieved without any network activity (e.g., solely based on local
* available information of other mechanisms), meaning that the result is
* directly available. Aggregated and raw observations answering a general
* {@link SiSRequest} might involve monitoring or active collection, therefore
* requiring a callback for result delivery.
*
* @author Bjoern Richerzhagen
*
*/
public interface SiSInformationConsumer {
/**
* Identifiers of aggregation functions supported by the SiS and (hopefully)
* the underlying monitoring solution.
*
* @author Bjoern Richerzhagen
*
*/
public enum AggregationFunction {
AVG, MIN, MAX, SUM, COUNT
}
/**
* Retrieve local state information about our own node.
* Source-component/layer/mechanism can be filtered via the
* {@link SiSRequest} - object if required.
*
* @param type
* @param request
* a request object specifying the desired information or
* SiSRequest.NONE if you do not want to specify request
* properties.
*
* @throws InformationNotAvailableException
* if no data can be derived
* @return
*/
public <T> T localState(SiSType<T> type, SiSRequest request)
throws InformationNotAvailableException;
/**
* Retrieve an observation of another node (identified by its
* {@link INodeID}). In an overlay sense, an observed node would be a
* neighbor in the overlay (e.g., a routing table entry). This method only
* uses local information or derivations, it does not trigger network
* operations. Use the callback-based method if you also allow collection of
* the requested value in the network.
*
* In case you do not yet know the ID of the node (e.g., you want to
* retrieve all known RTTs), just use the localObservationsOf method
* returning a map of {@link INodeID}s and values.
*
* @param observedNode
* id of the node you want to get information on (Use
* INodeID.get() to retrieve such an ID based on a number of
* input identifiers). If the ID is equal to (one of) our own
* local IDs, this method behaves just as localState(...) does.
* @param type
* @param request
* a request object specifying the desired information or
* SiSRequest.NONE if you do not want to specify request
* properties.
*
* @throws InformationNotAvailableException
* @return
*/
public <T> T localObservationOf(INodeID observedNode, SiSType<T> type,
SiSRequest request) throws InformationNotAvailableException;
/**
* Retrieve a map of all currently observed nodes and the available state
* information for the given {@link SiSType} and {@link SiSRequest}. Can be
* used, e.g., during the discovery phase of an overlay to retrieve the RTT
* to all currently known hosts measured by any other overlay.
*
* @param type
* @param request
* a request object specifying the desired information or
* SiSRequest.NONE if you do not want to specify request
* properties.
* @return a map, can be empty.
*/
public <T> Map<INodeID, T> allLocalObservations(SiSType<T> type,
SiSRequest request);
/**
* Request an aggregate according to the {@link SiSRequest}s parameters and
* the given {@link AggregationFunction}. Usually, these requests trigger
* monitoring. Sometimes, local data might be sufficient to answer the
* request, depending on the resolver logic - leading to an instant trigger
* of the provided callback.
*
* @param aggFunction
* desired aggregation
* @param type
* the {@link SiSType}
* @param request
* additional request properties
* @param callback
* result callback
* @return
*/
public <T> void aggregatedObservation(AggregationFunction aggFunction,
SiSType<T> type, SiSRequest request, SiSResultCallback<T> callback);
/**
* Requests raw values (i.e., per node) for the given type according to the
* {@link SiSRequest} parameters (e.g., regionally, globally, ...). Usually,
* this request involves active collection (monitoring) to be answered. If
* the request can be answered using local state (maybe from past requests)
* without violating the {@link SiSRequest} parameters, the callback will
* fire immediately with the local results.
*
* @param type
* the {@link SiSType}
* @param request
* additional request properties
* @param callback
* result callback, containing a map of values associated to node
* IDs
*/
public <T> void rawObservations(SiSType<T> type, SiSRequest request,
SiSResultCallback<Map<INodeID, T>> callback);
/**
* Create a plain request object for the given {@link SiSInfoProperties}.
* Use {@link SiSInfoProperties}.NONE in case you do not want to specify the
* information quality.
*
* @param infoProperties
* description of the desired information properties. Use
* {@link SiSInfoProperties}.NONE if you do not want to specify
* these.
*
* @return modifiable request object
*/
public SiSRequest newRequest(SiSInfoProperties infoProperties);
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.component.sis;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSType;
/**
* Interface used by the SiS to enable components to provide additional
* information (e.g., by adding local state to the SiS or by providing access to
* internal metrics).
*
* This interface is <strong>invoked</strong> by other components, not
* implemented by them. If you want to store state in the SiS, just invoke
* provide() on the {@link SiSComponent}. To describe your data source, make use
* of the {@link SiSInfoPropertiesFactory} and the resulting
* {@link SiSInfoProperties} objects reachable via the {@link SiSComponent}.
*
* @author Bjoern Richerzhagen
*
*/
public interface SiSInformationProvider {
/**
* Pure local node state, e.g. information that would be annotated to our
* own node object in an information graph. Could be, for example, a local
* buffer state.
*
* @param type
* @param dataCallback
* @param informationProperties
* @return
*/
public <T> SiSProviderHandle localNodeState(SiSType<T> type,
SiSDataCallback<T> dataCallback,
SiSInfoProperties informationProperties);
/**
* This method denotes that state about another node has been collected. In
* a graph-view, this is the information attached to the edge leading from
* our local node to the specified remote node, meaning
* "I know sth. about you or the connection to you".
*
* @param observedNode
* @param type
* @param dataCallback
* @param informationProperties
* @return
*/
public <T> SiSProviderHandle observedNodeState(INodeID observedNode,
SiSType<T> type, SiSDataCallback<T> dataCallback,
SiSInfoProperties informationProperties);
/**
* Revoke access to the information registered with the provided handle
*
* @param handle
*/
public void revoke(SiSProviderHandle handle);
/**
* A unique handle that allows the provider to revoke access to local
* metrics.
*
* @author Bjoern Richerzhagen
*
*/
public interface SiSProviderHandle {
// marker
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.component.sis;
import java.util.Map;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.sis.SiSInformationProvider.SiSProviderHandle;
import de.tudarmstadt.maki.simonstrator.api.component.sis.exception.InformationNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSType;
/**
* Logic that is to be implemented as part of the SiS to resolve information.
*
* @author Bjoern Richerzhagen
*
*/
public interface SiSInformationResolver {
/**
* Returns the local state, if the given request can be resolved locally
* (either by accessing the local storage for past values, or by querying
* one of the registered information providers).
*
* @param observedNode
* can be null, meaning we want to know sth. about our own local
* node.
* @param request
* the requests object contains QoS parameters related to the
* request (e.g., desired granularity, max timeout)
* @return local data
*/
public <T> T resolveLocally(INodeID observedNode, SiSType<T> type,
SiSRequest request) throws InformationNotAvailableException;
/**
* Returns a map of all currently available local observations of the given
* type.
*
* @param type
* @param request
* @return a (potentially empty) map of results
*/
public <T> Map<INodeID, T> getAllLocalObservations(SiSType<T> type,
SiSRequest request);
/**
* Adds a local resolver to the SiS
*
* @param observedNode
* (optional, can be null - null meaning: local node)
* @param type
* @param dataCallback
* @param informationProperties
* @return
*/
public <T> SiSProviderHandle addObservationProvider(INodeID observedNode,
SiSType<T> type, SiSDataCallback<T> dataCallback,
SiSInfoProperties informationProperties);
/**
* Removes the local provider with the given handle
*
* @param handle
*/
public void removeLocalProvider(SiSProviderHandle handle);
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of Simonstrator.KOM.
*
* Simonstrator.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 <http://www.gnu.org/licenses/>.
*
*/
package de.tudarmstadt.maki.simonstrator.api.component.sis;
import de.tudarmstadt.maki.simonstrator.api.component.sis.exception.InformationNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSType;
import de.tudarmstadt.maki.simonstrator.api.component.sis.type.SiSTypeDerivation;
/**
* Access current data hidden behind a Type. This is currently used for the
* {@link SiSTypeDerivation}s, but may also be an abstraction for the local
* storage later on.
*
* TODO this does explicitly not handle sets, as we define types to be flat.
*
* @author Bjoern Richerzhagen
*
*/
public interface SiSLocalData {
/**
* Returns the current value of the specified type
*
* @param type
* @param request
* (optional)
* @return
*/
public <T extends Object> T getValue(SiSType<T> type, SiSRequest request)
throws InformationNotAvailableException;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment