diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/ControlFlowModelingStage.java b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/ControlFlowModelingStage.java index b35f88a..1ff1884 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/ControlFlowModelingStage.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/ControlFlowModelingStage.java @@ -21,10 +21,7 @@ import models.dataFlowModel.ResourceNode; import java.awt.event.MouseListener; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class ControlFlowModelingStage extends Stage { public final int PORT_DIAMETER = 8; @@ -117,11 +114,11 @@ graph.getModel().beginUpdate(); try { // Create cells correspond to resource nodes for the PUSH/PULL layer. - Map pushResourceNodeCells = createResourceNodeCells(graph, controlFlowGraph, PUSH_FLOW_LAYER); - Map pullResourceNodeCells = createResourceNodeCells(graph, controlFlowGraph, PULL_FLOW_LAYER); + Map pushResourceNodeCells = createResourceNodeCells(graph, PUSH_FLOW_LAYER); + Map pullResourceNodeCells = createResourceNodeCells(graph, PULL_FLOW_LAYER); // Create cells correspond to event-channel nodes for the PUSH layer. - Map pushFlowEventNodeCells = createEventChannelNodeCells(graph, controlFlowGraph, PUSH_FLOW_LAYER); + Map pushFlowEventNodeCells = createEventChannelNodeCells(graph, PUSH_FLOW_LAYER); // Insert edges between the connected vertices graph = insertControlFlowEdges(PUSH_FLOW_LAYER, pushResourceNodeCells, pushFlowEventNodeCells); @@ -156,38 +153,45 @@ /** * Create and register a resource node cell on the specified layer. * - * @param graph The {@link mxGraph} to be modified. - * @param controlFlowGraph An instance of {@link ControlFlowGraph} to be used to construct a graph. - * @param layer The layer number + * @param graph The {@link mxGraph} to be modified. + * @param layer The layer number * @return The map of {@link ResourceNode} and its corresponding cell. */ - private Map createResourceNodeCells(final mxGraph graph, final ControlFlowGraph controlFlowGraph, final int layer) { - mxCell root = (mxCell) graph.getDefaultParent(); - mxCell layerCell = (mxCell) root.getChildAt(layer); - final Map resourceNodeCells = new HashMap<>(); - - CallGraph callGraph = null; - if (layer == PUSH_FLOW_LAYER) { - callGraph = controlFlowGraph.getPushCallGraph(); - } else if (layer == PULL_FLOW_LAYER) { - callGraph = controlFlowGraph.getPullCallGraph(); + private Map createResourceNodeCells(final mxGraph graph, final int layer) { + if (layer != PUSH_FLOW_LAYER && layer != PULL_FLOW_LAYER) { + throw new IllegalArgumentException("The layer number must be either PUSH_FLOW_LAYER or PULL_FLOW_LAYER."); } - for (ResourceNode rootNode : controlFlowGraph.getDataFlowGraph().getRootResourceNodes()) { - ResourcePath rootResourcePath = rootNode.getPrimaryResourcePath(); - - int width = calculateRequiredWidth(rootNode); - int height = calculateRequiredHeight(rootNode); - - String name = rootResourcePath.getLeafResourceName(); - if (rootResourcePath.endsWithParam()) { - name = "{" + rootResourcePath.getLastParam().toString() + "}"; + final mxCell root = (mxCell) graph.getDefaultParent(); + final mxCell layerCell = (mxCell) root.getChildAt(layer); + final Map resourceNodeCells = new HashMap<>(); + + final CallGraph callGraph = getCallGraph(layer); + if (callGraph == null) { + System.out.println("CallGraph is invalid."); + return Collections.emptyMap(); + } + + // TODO getRootNodes() から正しくルートに位置するノードを取得できていない(一部足りていないものがある) + for (Node rootNode : callGraph.getRootNodes()) { + if (!(rootNode instanceof StatefulObjectNode)) { + continue; } + ResourceNode resourceNode = ((StatefulObjectNode) rootNode).getResource(); + ResourcePath resourcePath = resourceNode.getPrimaryResourcePath(); - mxCell insertedCell = (mxCell) graph.insertVertex(layerCell, null, name, 20, 20, width, height, "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top"); // insert a resource as a vertex - resourceNodeCells.put(rootNode, insertedCell); + int width = calculateRequiredWidth(resourceNode); + int height = calculateRequiredHeight(resourceNode); + String name = resourcePath.getLeafResourceName(); + if (resourcePath.endsWithParam()) { + name = "{" + resourcePath.getLastParam().toString() + "}"; + } + String style = "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top"; - createChildResourceNodeCell(graph, insertedCell, rootNode, resourceNodeCells, (int) (width * getScale(rootNode.getChildren().size())), (int) (height * getScale(rootNode.getChildren().size())), callGraph); + mxCell insertedCell = (mxCell) graph.insertVertex(layerCell, null, name, 20, 20, width, height, style); // insert a resource as a vertex + resourceNodeCells.put(resourceNode, insertedCell); + + createChildResourceNodeCell(graph, insertedCell, resourceNode, resourceNodeCells, (int) (width * getScale(resourceNode.getChildren().size())), (int) (height * getScale(resourceNode.getChildren().size())), callGraph); } return resourceNodeCells; } @@ -200,8 +204,7 @@ */ private double getScale(int n) { if (n <= 1) return 0.6; - double val = (0.8 * Math.sin(Math.PI / n)) / (1.0 + 0.8 * Math.sin(Math.PI / n)); - return val; + return (0.8 * Math.sin(Math.PI / n)) / (1.0 + 0.8 * Math.sin(Math.PI / n)); } /** @@ -253,6 +256,7 @@ if (resourcePath.endsWithParam()) { name = "{" + resourcePath.getLastParam().toString() + "}"; } + String style = "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top"; mxGeometry parentGeo = parentCell.getGeometry(); double x = 0; @@ -269,7 +273,7 @@ } } - mxCell insertedCell = (mxCell) graph.insertVertex(parentCell, null, name, x, y, width, height, "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top"); // insert a resource as a vertex + mxCell insertedCell = (mxCell) graph.insertVertex(parentCell, null, name, x, y, width, height, style); // insert a resource as a vertex resourceNodeCells.put(childNode, insertedCell); createChildResourceNodeCell(graph, insertedCell, childNode, resourceNodeCells, (int) (width * getScale(childNode.getChildren().size())), (int) (height * getScale(childNode.getChildren().size())), callGraph); @@ -280,43 +284,52 @@ /** * Create and register a new graph cell for event channel nodes. * - * @param graph {@link mxGraph} instance to be modified. - * @param controlFlowGraph {@link ControlFlowGraph} instance to be used to construct a graph. - * @param layer The layer number. Only {@link Stage#PUSH_FLOW_LAYER} is supported. - * @return The map of {@link ChannelNode} and its corresponding cell. + * @param graph {@link mxGraph} instance to be modified. + * @param layer The layer number. Only {@link Stage#PUSH_FLOW_LAYER} is supported. + * @return The map of {@link EventChannelObjectNode} and its corresponding cell. */ - private Map createEventChannelNodeCells(final mxGraph graph, final ControlFlowGraph controlFlowGraph, final int layer) { + private Map createEventChannelNodeCells(final mxGraph graph, final int layer) { + if (layer != PUSH_FLOW_LAYER && layer != PULL_FLOW_LAYER) { + throw new IllegalArgumentException("The layer number must be either PUSH_FLOW_LAYER or PULL_FLOW_LAYER."); + } final mxCell rootCell = (mxCell) graph.getDefaultParent(); final mxCell layerCell = (mxCell) rootCell.getChildAt(layer); - final Map channelNodeCells = new HashMap<>(); - final Map outputChannelNodeCells = new HashMap<>(); + final Map eventChannelNodeCells = new HashMap<>(); + final Map outputEventChannelNodeCells = new HashMap<>(); - for (ChannelNode rootChannelNode : controlFlowGraph.getDataFlowGraph().getRootChannelNodes()) { - createEventChannelNodeCell(graph, layerCell, rootChannelNode, channelNodeCells, outputChannelNodeCells, MIN_EVENT_CHANNEL_NODE_WIDTH, MIN_EVENT_CHANNEL_NODE_HEIGHT); + final CallGraph callGraph = getCallGraph(layer); + if (callGraph == null) { + System.out.println("CallGraph is invalid."); + return Collections.emptyMap(); } - return channelNodeCells; + + for (Node rootNode : callGraph.getRootNodes()) { + if (!(rootNode instanceof EventChannelObjectNode)) { + continue; + } + final EventChannelObjectNode rootEventChannelNode = (EventChannelObjectNode) rootNode; + + createEventChannelNodeCell(graph, layerCell, rootEventChannelNode, eventChannelNodeCells, outputEventChannelNodeCells, MIN_EVENT_CHANNEL_NODE_WIDTH, MIN_EVENT_CHANNEL_NODE_HEIGHT); + } + return eventChannelNodeCells; } /** * Create and register a new cell for a specific channel node and its children * - * @param graph {@link mxGraph} instance to be modified. - * @param parentCell Parent cell of the new cell. - * @param channelNode {@link ChannelNode} instance to be registered. - * @param channelNodeCells {@link ChannelNode} and its corresponding cell. - * @param outputChannelNodeCells {@link ChannelNode} and its corresponding output port cell. - * @param cellWidth The width of a new cell. - * @param cellHeight The height of a new cell. + * @param graph {@link mxGraph} instance to be modified. + * @param parentCell Parent cell of the new cell. + * @param eventChannelNode {@link ChannelNode} instance to be registered. + * @param eventChannelNodeCells {@link ChannelNode} and its corresponding cell. + * @param outputEventChannelNodeCells {@link ChannelNode} and its corresponding output port cell. + * @param cellWidth The width of a new cell. + * @param cellHeight The height of a new cell. */ - private void createEventChannelNodeCell(final mxGraph graph, final mxCell parentCell, final ChannelNode channelNode, Map channelNodeCells, Map outputChannelNodeCells, double cellWidth, double cellHeight) { - DataTransferChannel channel = channelNode.getChannel(); - boolean isEventChannel = channel.getInputResources().isEmpty(); - if (!isEventChannel) { - return; - } + private void createEventChannelNodeCell(final mxGraph graph, final mxCell parentCell, final EventChannelObjectNode eventChannelNode, Map eventChannelNodeCells, Map outputEventChannelNodeCells, double cellWidth, double cellHeight) { + DataTransferChannel channel = eventChannelNode.getIOChannel(); // Corresponding cell is already created - if (outputChannelNodeCells.get(channelNode) != null) { + if (outputEventChannelNodeCells.get(eventChannelNode) != null) { return; } @@ -325,7 +338,7 @@ // Create and register a new cell for a channel node mxCell insertedChannelCell = (mxCell) graph.insertVertex(parentCell, null, channelName, cellWidth / 2, cellHeight / 4, cellWidth, cellHeight, "verticalAlign=top"); // insert a channel as a vertex - channelNodeCells.put(channelNode, insertedChannelCell); + eventChannelNodeCells.put(eventChannelNode, insertedChannelCell); // Attach an output port to the channel mxGeometry outputPortGeometry = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); @@ -334,30 +347,31 @@ outputPortGeometry.setRelative(true); outputPort.setVertex(true); graph.addCell(outputPort, insertedChannelCell); // insert the output port of a channel - outputChannelNodeCells.put(channelNode, outputPort); - - // Create child cells for the channel node recursively - for (ChannelNode childChannelNode : channelNode.getChildren()) { - createEventChannelNodeCell(graph, insertedChannelCell, childChannelNode, channelNodeCells, outputChannelNodeCells, cellWidth / 2.0, cellHeight / 2.0); - } + outputEventChannelNodeCells.put(eventChannelNode, outputPort); } /** * コントロールフローグラフの各頂点セルの間に, エッジのセルを追加する. * - * @param layerNumber エッジを追加したいmxGraphのレイヤー - * @param resNodeCells リソースと, その頂点セルのインスタンスのマップ - * @param eventChNodeCells イベントチャンネルと, その頂点セルのインスタンスのマップ + * @param layer エッジを追加したいmxGraphのレイヤー + * @param resourceNodeCells リソースと, その頂点セルのインスタンスのマップ + * @param eventChannelNodeCells イベントチャンネルと, その頂点セルのインスタンスのマップ */ - private mxGraph insertControlFlowEdges(final int layerNumber, final Map resNodeCells, final Map eventChNodeCells) { + private mxGraph insertControlFlowEdges(final int layer, final Map resourceNodeCells, final Map eventChannelNodeCells) { mxCell root = (mxCell) graph.getDefaultParent(); - mxCell layerCell = (mxCell) root.getChildAt(layerNumber); + mxCell layerCell = (mxCell) root.getChildAt(layer); - CallGraph callGraph = (layerNumber == PUSH_FLOW_LAYER) ? controlFlowGraph.getPushCallGraph() : controlFlowGraph.getPullCallGraph(); + CallGraph callGraph = getCallGraph(layer); + if (callGraph == null) { + System.out.println("CallGraph is invalid."); + return graph; + } - for (Edge callGraphEdge : callGraph.getEdges()) { - if (!(callGraphEdge instanceof CallEdge)) continue; - CallEdge callEdge = (CallEdge) callGraphEdge; + for (Edge edge : callGraph.getEdges()) { + if (!(edge instanceof CallEdge)) { + continue; + } + CallEdge callEdge = (CallEdge) edge; // エッジがノードと接続しているか? if (callEdge.getSource() == null || callEdge.getDestination() == null) continue; @@ -367,19 +381,20 @@ mxCell srcNodeCell = null; mxCell srcOutPortCell = null; - mxCell dstNodeCell = resNodeCells.get(dstResNode); + mxCell dstNodeCell = resourceNodeCells.get(dstResNode); if (callEdge.getSource() instanceof StatefulObjectNode) { srcResNode = ((StatefulObjectNode) callEdge.getSource()).getResource(); - srcNodeCell = resNodeCells.get(srcResNode); + srcNodeCell = resourceNodeCells.get(srcResNode); } else if (callEdge.getSource() instanceof EventChannelObjectNode) { srcResNode = callEdge.getSource(); EventChannelObjectNode eventChNode = (EventChannelObjectNode) srcResNode; DataTransferChannel channel = eventChNode.getIOChannel(); + // TODO: Suspicous call for getChannelNode() ChannelNode channelNode = controlFlowGraph.getDataFlowGraph().getChannelNode(channel); - if (eventChNodeCells == null) continue; - srcNodeCell = eventChNodeCells.get(channelNode); + if (eventChannelNodeCells == null) continue; + srcNodeCell = eventChannelNodeCells.get(channelNode); if (srcNodeCell == null) continue; srcOutPortCell = (mxCell) srcNodeCell.getChildAt(0); } else continue; @@ -432,4 +447,25 @@ } return path; } + + /** + * Retrieves the call graph associated with the specified control flow layer. + * + * @param layer The layer identifier. It determines whether to retrieve the PUSH or PULL call graph. + * Valid values are {@code PUSH_FLOW_LAYER} and {@code PULL_FLOW_LAYER}. + * @return The {@link CallGraph} instance for the specified layer, or {@code null} if the layer is invalid. + */ + private CallGraph getCallGraph(final int layer) { + switch (layer) { + case PUSH_FLOW_LAYER: { + return controlFlowGraph.getPushCallGraph(); + } + case PULL_FLOW_LAYER: { + return controlFlowGraph.getPullCallGraph(); + } + default: { + return null; + } + } + } }