123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651 |
- package de.tu_darmstadt.informatik.tk.scopviz.graphs;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.LinkedList;
- import org.graphstream.ui.graphicGraph.GraphPosLengthUtils;
- import de.tu_darmstadt.informatik.tk.scopviz.debug.Debug;
- import de.tu_darmstadt.informatik.tk.scopviz.main.Main;
- import de.tu_darmstadt.informatik.tk.scopviz.ui.MetricboxManager;
- /**
- * Class extending GraphManager. Offers the possibility to merge an underlay and
- * an operator graph.
- *
- *
- * @author Matthias Wilhelm
- *
- */
- public class MappingGraphManager extends GraphManager implements EdgeCreatedListener, NodeCreatedListener {
- public static final String UNDERLAY = "underlay";
- public static final String OPERATOR = "operator";
- public static final String ATTRIBUTE_KEY_PROCESS_NEED = "process-need";
- public static final String ATTRIBUTE_KEY_PROCESS_USE = "process-use";
- public static final String ATTRIBUTE_KEY_PROCESS_MAX = "process-max";
- public static final String ATTRIBUTE_KEY_MAPPING = "mapping";
- public static final String ATTRIBUTE_KEY_MAPPING_PARENT = "mapping-parent";
- public static final String ATTRIBUTE_KEY_MAPPING_PARENT_ID = "mapping-parent-id";
- public static final String UI_CLASS_MAPPING = "mapping";
- private static final double UNDERLAYER_MOVE_Y = 0;
- private static final double OPERATOR_MOVE_Y = 1.5;
- private static final double SCALE_WIDTH = 2;
- private static final double SCALE_HEIGHT = 1;
- /** Variables to keep track of new Nodes in the underlay graph */
- private boolean underlayNodesChanged = false;
- /** Variables to keep track of new Nodes in the operator graph */
- private boolean operatorNodesChanged = false;
- /** References to the underlay graph */
- GraphManager underlay;
- /** References to the operator graph */
- GraphManager operator;
- /** Map to store the id of the underlay and operator graphs IDs */
- HashMap<String, String> parentsID;
- /**
- * Creates a new manager for an empty graph. there is no need to check for
- * unique ID's for nodes and edges.
- *
- * @param graph
- * assumes a empty graph
- * @param underlay
- * the underlay graph
- * @param operator
- * the operator graph
- */
- public MappingGraphManager(MyGraph graph, GraphManager underlay, GraphManager operator) {
- super(graph);
- underlay.deselect();
- operator.deselect();
- this.underlay = underlay;
- this.operator = operator;
- parentsID = new HashMap<>();
- parentsID.put(UNDERLAY, underlay.getGraph().getId());
- parentsID.put(OPERATOR, operator.getGraph().getId());
- Debug.out("Created a new Mapping");
- graph.addSubGraph(underlay.getGraph());
- graph.addSubGraph(operator.getGraph());
- mergeGraph(underlay, UNDERLAY, UNDERLAYER_MOVE_Y);
- mergeGraph(operator, OPERATOR, OPERATOR_MOVE_Y);
- autoMapSourcesAndSinks(underlay, operator);
- view.getCamera().resetView();
- }
- /**
- *
- * @param g
- */
- public void loadGraph(MyGraph g) {
- // reset used capacity to 0 for every procEnabled node
- for (MyNode n : this.g.<MyNode>getNodeSet()) {
- if (hasClass(n, UI_CLASS_PROCESSING_ENABLED)) {
- resetCapacity(n);
- }
- }
- // recreates mapping edges from saved Attributes
- autoMapLoadedEdgeAttributes(underlay, operator);
- // recreates every mapping edge to properly calculate capacities
- for (MyEdge e : g.<MyEdge>getEdgeSet()) {
- if (e.getAttribute(ATTRIBUTE_KEY_MAPPING) != null && (boolean) e.getAttribute(ATTRIBUTE_KEY_MAPPING)) {
- createEdge(e.getSourceNode().getId(), e.getTargetNode().getId());
- }
- }
- }
- /**
- * Adds all nodes and edges of the given graph, adds a prefix to the ID of
- * every node and edge and offsets the normalized coordinates in y
- * direction.
- *
- * @param gm
- * the graph to be added
- * @param idPrefix
- * the prefix for the ID of every node and edge
- * @param moveY
- * the offset of the y coordinate
- */
- private void mergeGraph(GraphManager gm, String idPrefix, double moveY) {
- mergeNodes(gm, idPrefix, moveY);
- // Debug only
- int i = 0;
- for (MyEdge edge : gm.getGraph().<MyEdge>getEdgeSet()) {
- addEdge(edge, idPrefix);
- // Debug only
- i++;
- }
- Debug.out("added " + i + " Edge" + (i == 1 ? "" : "s") + " from \"" + idPrefix + "\"");
- }
- /**
- * Adds all nodes of the given graph, adds a prefix to the ID of every node
- * and offsets the normalized coordinates in y direction.
- *
- * @param gm
- * the graph to be added
- * @param idPrefix
- * the prefix for the ID of every node
- * @param moveY
- * the offset of the y coordinate
- */
- private void mergeNodes(GraphManager gm, String idPrefix, double moveY) {
- // precalculate scale and offset to normalize x coordinates
- double maxX = gm.getMaxX();
- double minX = gm.getMinX();
- double scaleX = SCALE_WIDTH / (maxX - minX);
- double addX = -minX * scaleX;
- if (maxX == minX) {
- scaleX = 0;
- addX = -SCALE_WIDTH / 2;
- } else {
- scaleX = SCALE_WIDTH / (maxX - minX);
- addX = -minX * scaleX;
- }
- // precalculate scale and offset to normalize y coordinates
- double maxY = gm.getMaxY();
- double minY = gm.getMinY();
- double scaleY;
- double addY;
- if (maxY == minY) {
- scaleY = 0;
- addY = SCALE_HEIGHT / 2 + moveY;
- } else {
- scaleY = SCALE_HEIGHT / (maxY - minY);
- addY = -minY * scaleY + moveY;
- }
- // Debug only
- int i = 0;
- // loops through all nodes, adds them if they don't exist already and
- // normalizes their coordinates
- for (MyNode node : gm.getGraph().<MyNode>getNodeSet()) {
- // add node if it doesn't exist
- MyNode newNode = getGraph().getNode(idPrefix + node.getId());
- if (newNode == null) {
- addNode(node, idPrefix);
- newNode = getGraph().getNode(idPrefix + node.getId());
- // Debug only
- i++;
- }
- // normalize coordinates
- double[] n = GraphPosLengthUtils.nodePosition(node);
- double cX = n[0];
- double x = cX * scaleX + addX;
- double cY = n[1];
- double y = cY * scaleY + addY;
- newNode.changeAttribute("x", x);
- newNode.changeAttribute("y", y);
- if (hasClass(newNode, UI_CLASS_PROCESSING_ENABLED)) {
- initCapacity(newNode);
- }
- }
- Debug.out("added " + i + " Node" + (i == 1 ? "" : "s") + " from \"" + idPrefix + "\"");
- }
- /**
- * Gets invoked by the GraphDisplayManager every time the mapping layer is
- * loaded. Checks whether nodes have been added to the parent graphs
- */
- public void activated() {
- if (underlayNodesChanged) {
- mergeNodes(underlay, UNDERLAY, UNDERLAYER_MOVE_Y);
- underlayNodesChanged = false;
- }
- if (operatorNodesChanged) {
- mergeNodes(operator, OPERATOR, OPERATOR_MOVE_Y);
- operatorNodesChanged = false;
- }
- }
- /**
- * Checks whether the given graph is underlay or operator graph to this
- * object or not.
- *
- * @param gm
- * the graph to check
- * @return true if the given graph is underlay or operator graph to this
- * graph. false otherwise
- */
- public boolean hasGraphManagerAsParent(GraphManager gm) {
- return (underlay.getGraph().getId().equals(gm.getGraph().getId()))
- || (operator.getGraph().getId().equals(gm.getGraph().getId()));
- }
- /**
- * Adds a <b>Copy</b> of the given Edge to the graph. The Copy retains the
- * ID and all attributes but adds the ID prefix in front of the all old IDs.
- *
- * @param e
- * the Edge to be added to the graph
- * @param idPrefix
- * the String to be added as prefix to the ID
- */
- private void addEdge(MyEdge e, String idPrefix) {
- HashMap<String, Object> attributes = new HashMap<>();
- for (String s : e.getAttributeKeySet()) {
- attributes.put(s, e.getAttribute(s));
- }
- attributes.put(ATTRIBUTE_KEY_MAPPING, false);
- attributes.put(ATTRIBUTE_KEY_MAPPING_PARENT, idPrefix);
- attributes.put(ATTRIBUTE_KEY_MAPPING_PARENT_ID, parentsID.get(idPrefix));
- g.addEdge(idPrefix + e.getId(), idPrefix + e.getSourceNode().getId(), idPrefix + e.getTargetNode().getId(),
- e.isDirected());
- g.getEdge(idPrefix + e.getId()).addAttributes(attributes);
- }
- @Override
- public void addNode(MyNode n) {
- // This function mustn't be called.
- Debug.out("Someone called addNode(Node n) with a MappingGraphManager");
- }
- /**
- * Adds a <b>Copy</b> of the given Node to the graph. The Copy retains the
- * ID and all attributes but adds the ID prefix in front of the old ID.
- *
- * @param n
- * the Node to be added to the graph
- * @param idPrefix
- * the String to be added as prefix to the ID
- */
- private void addNode(MyNode n, String idPrefix) {
- HashMap<String, Object> attributes = new HashMap<>();
- for (String s : n.getAttributeKeySet()) {
- attributes.put(s, n.getAttribute(s));
- }
- attributes.put(ATTRIBUTE_KEY_MAPPING_PARENT, idPrefix);
- attributes.put(ATTRIBUTE_KEY_MAPPING_PARENT_ID, parentsID.get(idPrefix));
- g.addNode(idPrefix + n.getId());
- g.getNode(idPrefix + n.getId()).addAttributes(attributes);
- g.<MyNode>getNode(idPrefix + n.getId()).addCSSClass("onMapping");
- }
- @Override
- public void nodeCreated(MyNode n, String graphID) {
- if (graphID.equals(underlay.getGraph().getId()))
- underlayNodesChanged = true;
- else if (graphID.equals(operator.getGraph().getId()))
- operatorNodesChanged = true;
- }
- @Override
- public void edgeCreated(MyEdge e, String graphID) {
- if (graphID.equals(underlay.getGraph().getId()))
- addEdge(e, UNDERLAY);
- else if (graphID.equals(operator.getGraph().getId()))
- addEdge(e, OPERATOR);
- }
- @Override
- public void createEdges(String id) {
- super.createEdges(id);
- if (lastClickedID != null) {
- Double need = g.getNode(lastClickedID).getAttribute(ATTRIBUTE_KEY_PROCESS_NEED);
- if (need != null)
- for (MyNode n : g.<MyNode>getNodeSet())
- if (hasClass(n, UI_CLASS_PROCESSING_ENABLED))
- showExpectedCapacity(n, need);
- }
- }
- @Override
- protected void deselectNodesAfterEdgeCreation(String nodeID) {
- super.deselectNodesAfterEdgeCreation(nodeID);
- for (MyNode n : g.<MyNode>getNodeSet())
- if (hasClass(n, UI_CLASS_PROCESSING_ENABLED))
- showExpectedCapacity(n, 0);
- }
- /**
- * checks whether the Node can handle the load first.<br/>
- * creates a edge between to nodes
- */
- @Override
- public boolean createEdge(String to, String from) {
- MyNode fromNode = getGraph().getNode(from);
- MyNode toNode = getGraph().getNode(to);
- if (fromNode.hasEdgeBetween(to))
- return false;
- for (MyEdge e : fromNode.<MyEdge>getEdgeSet()) {
- Boolean mapped = e.getAttribute("mapping");
- if (mapped != null && mapped)
- return false;
- }
- String fromParent = fromNode.getAttribute(ATTRIBUTE_KEY_MAPPING_PARENT);
- String toParent = toNode.getAttribute(ATTRIBUTE_KEY_MAPPING_PARENT);
- if (fromParent == null || toParent == null)
- return false;
- if (fromParent.equals(toParent)) {
- deselectNodesAfterEdgeCreation(lastClickedID);
- /*
- * lastClickedID = to; selectNodeForEdgeCreation(lastClickedID);
- */
- return false;
- }
- String newID = Main.getInstance().getUnusedID();
- MyEdge e;
- MyNode underlayNode;
- MyNode operatorNode;
- if (fromParent.equals(UNDERLAY)) {
- underlayNode = fromNode;
- operatorNode = toNode;
- } else if (toParent.equals(UNDERLAY)) {
- underlayNode = toNode;
- operatorNode = fromNode;
- } else
- return false;
- // check if processing enabled node
- if (!hasClass(underlayNode, UI_CLASS_PROCESSING_ENABLED))
- return false;
- // check and update capacity
- if (!addMapping(underlayNode, operatorNode)) {
- Debug.out("Could not place Mapping Edge due to insufficient capacity!", 2);
- return false;
- }
- e = getGraph().addEdge(newID, operatorNode, underlayNode, true);
- Debug.out("Created an directed edge with Id " + newID + " from " + operatorNode + " to " + underlayNode);
- // adds an Attribute for loading Edges from file
- GraphHelper.propagateAttribute(this.g, underlayNode, "mappingEdge", newID);
- underlay.getGraph().getNode(underlayNode.getId().substring(8)).addAttribute("mappingEdge", newID);
- GraphHelper.propagateAttribute(this.g, operatorNode, "mappingEdge", newID);
- operator.getGraph().getNode(operatorNode.getId().substring(8)).addAttribute("mappingEdge", newID);
- e.addAttribute("ui.class", UI_CLASS_MAPPING);
- e.addAttribute(ATTRIBUTE_KEY_MAPPING, true);
- selectEdge(newID);
- MetricboxManager.updateMetrics();
- return true;
- }
- /**
- * Initialize the pie chart for the given node. It uses the process_use and
- * process_max values of the given node. If process_max is null or 0 it
- * won't do anything. If process_use is null it will be initialized to 0.
- *
- * @param underlayNode
- * The Node for which the pie chart should be initialized
- */
- private void initCapacity(MyNode underlayNode) {
- Double used = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_USE);
- Double max = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_MAX);
- if (max == null || max == 0)
- return;
- if (used == null)
- used = new Double(0);
- double[] pieValues = { used / max, 0, 1 - used / max };
- underlayNode.setAttribute("ui.pie-values", pieValues);
- underlayNode.setAttribute(ATTRIBUTE_KEY_PROCESS_USE, used);
- }
- /**
- * Resets the pie chart for the given node. If process_max is null or 0 it
- * won't display anything. Process_use set to 0.
- *
- * @param underlayNode
- * The Node for which the pie chart should be initialized
- */
- private void resetCapacity(MyNode underlayNode) {
- Double used = new Double(0);
- underlayNode.setAttribute(ATTRIBUTE_KEY_PROCESS_USE, used);
- Double max = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_MAX);
- if (max == null || max == 0)
- return;
- double[] pieValues = { 0, 0, 1 };
- underlayNode.setAttribute("ui.pie-values", pieValues);
- }
- /**
- * Checks and updates the Capacity for a procEn node. Tries to map the given
- * operatorNode to the given underlayNode.
- *
- * @param underlayNode
- * The underlayNode the operatorNode gets mapped to
- * @param operatorNode
- * The operatorNode which gets mapped
- * @return true if the mapping was successful. false otherwise.
- */
- private boolean addMapping(MyNode underlayNode, MyNode operatorNode) {
- Double needed = operatorNode.getAttribute(ATTRIBUTE_KEY_PROCESS_NEED);
- if (needed == null)
- return true;
- return changeCapacity(underlayNode, needed);
- }
- /**
- * Checks and updates the Capacity for a procEn node. Tries to unmap the
- * given operatorNode to the given underlayNode.
- *
- * @param underlayNode
- * The underlayNode the operatorNode gets mapped to
- * @param operatorNode
- * The operatorNode which gets mapped
- * @return true if the mapping was successful. false otherwise.
- */
- private boolean removeMapping(MyNode underlayNode, MyNode operatorNode) {
- Double needed = operatorNode.getAttribute(ATTRIBUTE_KEY_PROCESS_NEED);
- if (needed == null)
- return true;
- return changeCapacity(underlayNode, -needed);
- }
- /**
- * Checks and updates the Capacity for a procEn node. Tries to map the
- * capacity to the given underlayNode.
- *
- * @param underlayNode
- * The underlayNode which capacity gets updated
- * @param capacity
- * The capacity. may be positive or negative
- * @return true if the capacity change was successful. false otherwise.
- */
- private boolean changeCapacity(MyNode underlayNode, double capacity) {
- Double needed = capacity;
- Double used = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_USE);
- Double max = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_MAX);
- if (needed == 0)
- return true;
- if (max == null || max == 0)
- if (needed > 0)
- return false;
- if (used == null)
- used = new Double(0);
- if (used + needed > max)
- return false;
- used += needed;
- double[] pieValues = { used / max, 0, 1 - used / max };
- underlayNode.setAttribute("ui.pie-values", pieValues);
- underlayNode.setAttribute(ATTRIBUTE_KEY_PROCESS_USE, used);
- return true;
- }
- /**
- * Displays the capacity change to the node if the needed Cost is applied.
- *
- * @param underlayNode
- * The node which gets updated
- * @param need
- * the capacity change
- */
- private void showExpectedCapacity(MyNode underlayNode, double need) {
- Double used = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_USE);
- Double max = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_MAX);
- if (max == null || max == 0)
- return;
- if (used == null)
- used = new Double(0);
- double[] pieValues = { used / max, 0, 1 - used / max, 0 };
- if (need + used > max) {
- pieValues[3] = pieValues[2];
- pieValues[2] = 0;
- } else {
- pieValues[1] = need / max;
- pieValues[2] -= need / max;
- }
- underlayNode.setAttribute("ui.pie-values", pieValues);
- underlayNode.setAttribute(ATTRIBUTE_KEY_PROCESS_USE, used);
- }
- @Override
- protected boolean selectNodeForEdgeCreation(String nodeID) {
- MyNode n = g.getNode(nodeID);
- String parent = n.getAttribute(ATTRIBUTE_KEY_MAPPING_PARENT);
- if (parent == null)
- return false;
- if (parent.equals(OPERATOR)) {
- for (MyEdge e : n.<MyEdge>getEdgeSet()) {
- Boolean isMapped = e.getAttribute(ATTRIBUTE_KEY_MAPPING);
- if (isMapped != null && isMapped)
- return false;
- }
- return super.selectNodeForEdgeCreation(nodeID);
- }
- if (hasClass(n, UI_CLASS_PROCESSING_ENABLED))
- return super.selectNodeForEdgeCreation(nodeID);
- return false;
- }
- @Override
- public void deleteEdge(final String id) {
- MyEdge e = g.getEdge(id);
- if ((boolean) e.getAttribute(ATTRIBUTE_KEY_MAPPING)) {
- MyNode operatorNode = e.getSourceNode();
- MyNode underlayNode = e.getTargetNode();
- // delete mapping attriute
- GraphHelper.propagateAttribute(this.g, underlayNode, "mappingEdge", null);
- underlay.getGraph().getNode(underlayNode.getId().substring(8)).removeAttribute("mappingEdge");
- GraphHelper.propagateAttribute(this.g, operatorNode, "mappingEdge", null);
- operator.getGraph().getNode(operatorNode.getId().substring(8)).removeAttribute("mappingEdge");
- removeMapping(underlayNode, operatorNode);
- super.deleteEdge(id);
- }
- MetricboxManager.updateMetrics();
- }
- @Override
- public void deleteNode(String id) {
- Debug.out("default delete Node prevented");
- }
- @Override
- public void undelete() {
- super.undelete();
- for (MyEdge e : deletedEdges) {
- if ((boolean) e.getAttribute(ATTRIBUTE_KEY_MAPPING))
- changeCapacity(e.getTargetNode(), e.getSourceNode().getAttribute(ATTRIBUTE_KEY_PROCESS_NEED));
- }
- }
- private void autoMapSourcesAndSinks(GraphManager underlay, GraphManager operator) {
- // TODO Andere Farbe für automatisch erstellte Mappingkanten von Quellen
- // und Senken
- for (MyNode operatorNode : getOperatorNodeSet()) {
- if (operatorNode.getAttribute("typeofNode").toString().equals("source")) {
- for (MyNode underlayNode : getUnderlayNodeSet()) {
- if (operatorNode.getAttribute("identifier") != null && operatorNode.getAttribute("identifier")
- .equals(underlayNode.getAttribute("identifier"))) {
- String newID = Main.getInstance().getUnusedID(this);
- MyEdge e = getGraph().addEdge(newID, operatorNode, underlayNode, true);
- Debug.out("Created an directed edge with Id " + newID + " from " + operatorNode + " to "
- + underlayNode);
- e.addAttribute("ui.class", UI_CLASS_MAPPING);
- e.addAttribute(ATTRIBUTE_KEY_MAPPING, true);
- }
- }
- } else if (operatorNode.getAttribute("typeofNode").equals("sink")) {
- for (MyNode underlayNode : getUnderlayNodeSet()) {
- String identifier = operatorNode.getAttribute("identifier");
- if (identifier != null && identifier.equals(underlayNode.getAttribute("identifier"))) {
- String newID = Main.getInstance().getUnusedID(this);
- MyEdge e = getGraph().addEdge(newID, operatorNode, underlayNode, true);
- Debug.out("Created an directed edge with Id " + newID + " from " + operatorNode + " to "
- + underlayNode);
- e.addAttribute("ui.class", UI_CLASS_MAPPING);
- e.addAttribute(ATTRIBUTE_KEY_MAPPING, true);
- }
- }
- }
- }
- }
- private Collection<MyNode> getOperatorNodeSet() {
- LinkedList<MyNode> result = new LinkedList<MyNode>();
- for (MyNode n : getGraph().<MyNode>getNodeSet()) {
- if (n.getAttribute(ATTRIBUTE_KEY_MAPPING_PARENT) == OPERATOR) {
- result.add(n);
- }
- }
- return result;
- }
- private Collection<MyNode> getUnderlayNodeSet() {
- LinkedList<MyNode> result = new LinkedList<MyNode>();
- for (MyNode n : getGraph().<MyNode>getNodeSet()) {
- if (n.getAttribute(ATTRIBUTE_KEY_MAPPING_PARENT) == UNDERLAY) {
- result.add(n);
- }
- }
- return result;
- }
- private void autoMapLoadedEdgeAttributes(GraphManager underlay2, GraphManager operator2) {
- for (MyNode operatorNode : getOperatorNodeSet()) {
- for (MyNode underlayNode : getUnderlayNodeSet()) {
- String identifier = operatorNode.getAttribute("mappingEdge");
- if (identifier != null && identifier.equals(underlayNode.getAttribute("mappingEdge"))) {
- createEdge(operatorNode.getId(), underlayNode.getId());
- }
- }
- }
- }
- }
|