diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java b/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java index f54aea4..a392b11 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Set; import models.*; import models.algebra.*; @@ -75,12 +76,55 @@ * @return annotated data flow graph */ static public DataFlowGraph annotateWithSelectableDataTransferAttiribute(DataFlowGraph graph) { - List resNodes = new ArrayList<>(graph.getResourceNodes()); - // set push only attributes + HashSet unvisitedNodes = new HashSet<>(graph.getResourceNodes()); + // Turn push only for (Node resNode: graph.getResourceNodes()) { - if (resNodes.contains(resNode) && ((StoreAttribute) ((ResourceNode) resNode).getAttribute()).isNeeded()) { - resNodes.remove(resNode); - trackEdges(resNode, resNodes); + if (unvisitedNodes.contains(resNode) && ((StoreAttribute) ((ResourceNode) resNode).getAttribute()).isNeeded()) { + unvisitedNodes.remove(resNode); + trackEdgesBackwardForPush(resNode, unvisitedNodes); + } + } + // Turn push/pull only with respect to channel hierarchies. + while (!unvisitedNodes.isEmpty()) { + Node resNode = unvisitedNodes.iterator().next(); + unvisitedNodes.remove(resNode); + for (Edge chToRes : ((ResourceNode) resNode).getInEdges()) { + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + // Should take into account the channel hierarchy. + boolean pullContained = false; + Set ancestorChannels = chNode.getAncestors(); + for (ChannelNode ancestorCh: ancestorChannels) { + for (Edge resToCh: ancestorCh.getInEdges()) { + ResourceNode srcResNode = (ResourceNode) resToCh.getSource(); + DataTransferChannel ch = (DataTransferChannel) ancestorCh.getChannel(); + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.isOutside()) { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PULL); // To refer to outside resource. + ((DataFlowEdge) resToCh).setAttribute(ppat); + pullContained = true; + } else { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PUSH); // For broadcasting transfer. + ((DataFlowEdge) resToCh).setAttribute(ppat); + unvisitedNodes.remove(srcResNode); + trackEdgesBackwardForPush(srcResNode, unvisitedNodes); + } + } + } + } + Set descendantChannels = chNode.getDescendants(); + for (ChannelNode descendantCh: descendantChannels) { + for (Edge resToCh: descendantCh.getInEdges()) { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PULL); // For collecting transfer. + ((DataFlowEdge) resToCh).setAttribute(ppat); + pullContained = true; + } + } + if (pullContained) { + trackEdgesForwardForPull(resNode, unvisitedNodes); + } } } // set push/pull attributes to the remaining edges @@ -96,18 +140,57 @@ return graph; } - static private void trackEdges(Node resNode, List resNodes) { - // recursively set push only attributes to input side edges + static private void trackEdgesBackwardForPush(Node resNode, HashSet unvisitedNodes) { + // recursively turn push only backward in data-flow. for (Edge chToRes : ((ResourceNode) resNode).getInEdges()) { - Node chNode = chToRes.getSource(); - for (Edge resToCh : ((ChannelNode) chNode).getInEdges()) { + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + // Should take into account the channel hierarchy. + Set ancestorChannels = chNode.getAncestors(); + Set descendantChannels = chNode.getDescendants(); + Set inEdges = new HashSet<>(); + inEdges.addAll(chNode.getInEdges()); + for (ChannelNode ancestorCh: ancestorChannels) { + inEdges.addAll(ancestorCh.getInEdges()); + } + for (ChannelNode descendantCh: descendantChannels) { + inEdges.addAll(descendantCh.getInEdges()); + } + for (Edge resToCh: inEdges) { PushPullAttribute ppat = new PushPullAttribute(); ppat.addOption(PushPullValue.PUSH); ((DataFlowEdge) resToCh).setAttribute(ppat); Node resNode2 = resToCh.getSource(); - if (resNodes.contains(resNode2)) { - resNodes.remove(resNode2); - trackEdges(resNode2, resNodes); + if (unvisitedNodes.contains(resNode2)) { + unvisitedNodes.remove(resNode2); + trackEdgesBackwardForPush(resNode2, unvisitedNodes); + } + } + } + } + + private static void trackEdgesForwardForPull(Node resNode, HashSet unvisitedNodes) { + // recursively turn pull only forward in data-flow. + for (Edge resToCh : ((ResourceNode) resNode).getOutEdges()) { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PULL); + ((DataFlowEdge) resToCh).setAttribute(ppat); + ChannelNode chNode = (ChannelNode) resToCh.getDestination(); + // Should take into account the channel hierarchy. + Set ancestorChannels = chNode.getAncestors(); + Set descendantChannels = chNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(chNode.getOutEdges()); + for (ChannelNode ancestorCh: ancestorChannels) { + outEdges.addAll(ancestorCh.getOutEdges()); + } + for (ChannelNode descendantCh: descendantChannels) { + outEdges.addAll(descendantCh.getOutEdges()); + } + for (Edge chToRes: outEdges) { + Node resNode2 = chToRes.getDestination(); + if (unvisitedNodes.contains(resNode2)) { + unvisitedNodes.remove(resNode2); + trackEdgesForwardForPull(resNode2, unvisitedNodes); } } } diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java index 3c8dbc0..30b667a 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java @@ -178,9 +178,6 @@ // Force to change PushPullSelectionStage to construct mxGraph boolean stageChanged = changeStage(STAGE_PUSH_PULL_SELECTION); - if (stageChanged && curStage instanceof PushPullSelectionStage) { - ((PushPullSelectionStage) curStage).constructGraph(); // Construction of data-flow graph - } // Set layout setDAGLayout(); @@ -214,9 +211,6 @@ // Force to change PushPullSelectionStage to construct mxGraph boolean stageChanged = changeStage(STAGE_PUSH_PULL_SELECTION); - if (stageChanged && curStage instanceof PushPullSelectionStage) { - ((PushPullSelectionStage) curStage).constructGraph(); // Construction of data-flow graph - } // Restore the geometry parser.doParseGeometry(graph); diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java index 06b5b47..b1e32e7 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java @@ -81,8 +81,12 @@ private DataFlowGraph analyzeDataTransferModel(DataTransferModel model) { DataFlowGraph flowGraph = DataTransferModelAnalyzer.createDataFlowGraphWithStateStoringAttribute(model); - DataFlowGraph dataFlowGraph = DataTransferModelAnalyzer.annotateWithSelectableDataTransferAttiribute(flowGraph); - updateEdgeAttributes(dataFlowGraph); + dataFlowGraph = DataTransferModelAnalyzer.annotateWithSelectableDataTransferAttiribute(flowGraph); + mxCell parent = (mxCell) graph.getDefaultParent(); + if (parent.getChildCount() == 0) { + constructGraph(); // Construct data-flow graph (on file open action) + } + updateEdgeAttributes(dataFlowGraph); // Update push/pull selection pull-downs return dataFlowGraph; } diff --git a/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/ControlFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/ControlFlowGraph.java index 083d3b0..1248b73 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/ControlFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/ControlFlowGraph.java @@ -25,22 +25,28 @@ this.dataFlowGraph = dataFlowGraph; this.pushCallGraph = new CallGraph(); this.pullCallGraph = new CallGraph(); - for (Edge e: dataFlowGraph.getEdges()) { - PushPullAttribute pushPull = ((PushPullAttribute) ((DataFlowEdge) e).getAttribute()); - ResourceNode srcNode = (ResourceNode) e.getSource(); - ResourceNode dstNode = (ResourceNode) e.getDestination(); - if (pushPull.getOptions().get(0) == PushPullValue.PUSH) { - // same direction as the data flow - pushCallGraph.addEdge(srcNode, dstNode, PushPullValue.PUSH); - } else { - // reverse direction to the data flow - pullCallGraph.addEdge(dstNode, srcNode, PushPullValue.PULL); + 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 chNode = (ChannelNode) resToCh.getDestination(); + for (Edge chToRes: chNode.getOutEdges()) { + ResourceNode dstResNode = (ResourceNode) chToRes.getDestination(); + 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 cio = (DataTransferChannel) ch; - EventChannelObjectNode srcNode = new EventChannelObjectNode(cio); - for (ChannelMember cm: cio.getChannelMembers()) { + 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) { @@ -55,7 +61,7 @@ pushCallGraph.addNode(dstResNode); dstNode = pushCallGraph.getStatefulObjectNode(dstResNode); } - // from an I/O channel to a resource + // from an input event channel to a resource pushCallGraph.insertEdge(srcNode, dstNode, PushPullValue.PUSH, 0); } } @@ -64,6 +70,14 @@ public DataFlowGraph getDataFlowGraph() { return dataFlowGraph; } + + public CallGraph getPushCallGraph() { + return pushCallGraph; + } + + public CallGraph getPullCallGraph() { + return pullCallGraph; + } @Override public Map> getAllComponentNodes() {