package models.controlFlowModel;
import models.DirectedGraph;
import models.Node;
import models.dataFlowModel.PushPullValue;
import models.dataFlowModel.ResourceNode;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* {@link CallGraph} is a directed graph that represents the control flow between resources
*/
public class CallGraph extends DirectedGraph {
protected Map<ResourceNode, StatefulObjectNode> statefulObjMap;
public CallGraph() {
statefulObjMap = new HashMap<>();
}
/**
* Add a node to the graph.
*
* @param node The node to be added.
*/
public void addNode(Node node) {
if (node instanceof ResourceNode) {
ResourceNode resNode = (ResourceNode) node;
StatefulObjectNode objNode = statefulObjMap.get(resNode);
if (objNode == null) {
objNode = new StatefulObjectNode(resNode);
statefulObjMap.put(resNode, objNode);
super.addNode(objNode);
}
} else if (node instanceof StatefulObjectNode) {
StatefulObjectNode objNode = (StatefulObjectNode) node;
if (statefulObjMap.get(objNode.getResource()) == null) {
statefulObjMap.put(objNode.getResource(), objNode);
super.addNode(objNode);
}
} else {
super.addNode(node);
}
}
/**
* Add new call edge from {@code srcResNode} to {@code dstResNode} with PUSH / PULL selection.
*
* @param srcResNode The resource node the edge starts from.
* @param dstResNode The resource node the edge ends at.
* @param selectedOption PUSH / PULL
*/
public void addEdge(ResourceNode srcResNode, ResourceNode dstResNode, PushPullValue selectedOption) {
addNode(srcResNode);
addNode(dstResNode);
addEdge(new CallEdge(getStatefulObjectNode(srcResNode), getStatefulObjectNode(dstResNode), selectedOption));
}
/**
* Insert an edge into the graph.
*
* @param srcObjNode The source node of the edge to be inserted
* @param dstObjNode The destination node of the edge to be inserted
* @param selectedOption PUSH or PULL
* @param n The calling order of the edge
*/
public void insertEdge(ObjectNode srcObjNode, ObjectNode dstObjNode, PushPullValue selectedOption, int n) {
CallEdge edge = new CallEdge(srcObjNode, dstObjNode, selectedOption);
simpleAddEdge(edge);
addNode(srcObjNode);
addNode(dstObjNode);
srcObjNode.insertOutEdge(edge, n);
dstObjNode.addInEdge(edge);
}
public StatefulObjectNode getStatefulObjectNode(ResourceNode resNode) {
return statefulObjMap.get(resNode);
}
public Set<Node> getRootNodes() {
Set<Node> roots = new HashSet<>();
for (Node node : getNodes()) {
if (node instanceof StatefulObjectNode) {
StatefulObjectNode statefulObjectNode = (StatefulObjectNode) node;
if (statefulObjectNode.getResource().getResourceHierarchy().getParent() == null) {
roots.add(node);
}
} else {
if (node.getIndegree() == 0) {
roots.add(node);
}
}
}
return roots;
}
}