Newer
Older
AlgebraicDataflowArchitectureModel / AlgebraicDataflowArchitectureModel / src / models / controlFlowModel / ControlFlowGraph.java
package models.controlFlowModel;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import generators.CodeGenerator;
import models.Edge;
import models.Node;
import models.algebra.Expression;
import models.algebra.Term;
import models.algebra.Variable;
import models.dataConstraintModel.Channel;
import models.dataConstraintModel.ChannelMember;
import models.DirectedGraph;
import models.dataFlowModel.*;

public class ControlFlowGraph extends DirectedGraph implements IFlowGraph {
	private DataFlowGraph dataFlowGraph;
	private CallGraph pushCallGraph;
	private CallGraph pullCallGraph;
	
	public ControlFlowGraph(DataFlowGraph dataFlowGraph, DataTransferModel model) {
		this.dataFlowGraph = dataFlowGraph;
		this.pushCallGraph = new CallGraph();
		this.pullCallGraph = new CallGraph();
		for (Edge resToCh: dataFlowGraph.getEdges()) {
			if (!((DataFlowEdge) resToCh).isChannelToResource()) {
				// A resource to channel edge
				PushPullAttribute pushPull = ((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute());
				ResourceNode srcResNode = (ResourceNode) resToCh.getSource();
				ChannelNode directDstChNode = (ChannelNode) resToCh.getDestination();
				// Should take into account the channel hierarchy.
				Set<ChannelNode> ancestorDstChannels = directDstChNode.getAncestors();
				Set<ChannelNode> descendantDstChannels = directDstChNode.getDescendants();
				Set<Edge> outEdges = new HashSet<>();
				outEdges.addAll(directDstChNode.getOutEdges());
				for (ChannelNode ancestorDst: ancestorDstChannels) {
					outEdges.addAll(ancestorDst.getOutEdges());
				}
				for (ChannelNode descendantDst: descendantDstChannels) {
					outEdges.addAll(descendantDst.getOutEdges());
				}
				for (Edge chToRes: outEdges) {
					ResourceNode dstResNode = (ResourceNode) chToRes.getDestination();
					if (!CodeGenerator.generatesComponent(srcResNode.getResourceHierarchy())) {
						srcResNode = srcResNode.getParent();
					}
					if (!CodeGenerator.generatesComponent(dstResNode.getResourceHierarchy())) {
						dstResNode = dstResNode.getParent();
					}
					if (!srcResNode.getResourceHierarchy().equals(dstResNode.getResourceHierarchy())) {
						if (pushPull.getOptions().get(0) == PushPullValue.PUSH) {
							// same direction as the data flow
							pushCallGraph.addEdge(srcResNode, dstResNode, PushPullValue.PUSH);
						} else {
							// reverse direction to the data flow
							pullCallGraph.addEdge(dstResNode, srcResNode, PushPullValue.PULL);
						}
					}
				}
			}
		}
		for (Channel ch: model.getInputChannels()) {
			DataTransferChannel evCh = (DataTransferChannel) ch;
			EventChannelObjectNode srcNode = new EventChannelObjectNode(evCh);
			for (ChannelMember cm: evCh.getChannelMembers()) {
				if (srcNode.getName() == null) {
					Expression exp = cm.getStateTransition().getMessageExpression();
					if (exp instanceof Term) {
						srcNode.setName(((Term) exp).getSymbol().getName());
					} else if (exp instanceof Variable) {
						srcNode.setName(((Variable) exp).getName());
					}
				}
				for (ResourceNode dstResNode: dataFlowGraph.getResourceNodes(cm.getResource().getResourceHierarchy())) {
					if (!CodeGenerator.generatesComponent(dstResNode.getResourceHierarchy())) {
						dstResNode = dstResNode.getParent();
					}
					StatefulObjectNode dstNode = pushCallGraph.getStatefulObjectNode(dstResNode);
					if (dstNode == null) {
						pushCallGraph.addNode(dstResNode);
						dstNode = pushCallGraph.getStatefulObjectNode(dstResNode);
					}
					// from an input event channel to a resource
					pushCallGraph.insertEdge(srcNode, dstNode, PushPullValue.PUSH, 0);
				}
			}
		}
	}
	
	public DataFlowGraph getDataFlowGraph() {
		return dataFlowGraph;
	}
	
	public CallGraph getPushCallGraph() {
		return pushCallGraph;
	}
	
	public CallGraph getPullCallGraph() {
		return pullCallGraph;
	}

	@Override
	public Map<Node, Set<Node>> getAllComponentNodes() {
		Map<Node, Set<Node>> allNodeSets = new HashMap<>();
		for (Node n: pushCallGraph.getNodes()) {
			Set<Node> nodeSet = new HashSet<>();
			nodeSet.add(n);
			allNodeSets.put(n, nodeSet);
		}
		for (Node n: pullCallGraph.getNodes()) {
			if (n instanceof StatefulObjectNode) {
				ResourceNode resNode = ((StatefulObjectNode) n).getResource();
				Set<Node> nodeSet = null;
				if (pushCallGraph.getStatefulObjectNode(resNode) != null) {
					// Merge a stateful object node in the push call graph and that in the pull call graph.
					nodeSet = allNodeSets.get(pushCallGraph.getStatefulObjectNode(resNode));
				} else {
					nodeSet = new HashSet<>();
				}
				nodeSet.add(n);
				allNodeSets.put(n, nodeSet);
			} else {
				Set<Node> nodeSet = new HashSet<>();
				nodeSet.add(n);
				allNodeSets.put(n, nodeSet);
			}
		}
		return allNodeSets;
	}
}