MappingGraphManager.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. package de.tu_darmstadt.informatik.tk.scopviz.main;
  2. import java.util.HashMap;
  3. import org.graphstream.algorithm.Toolkit;
  4. import org.graphstream.graph.Edge;
  5. import org.graphstream.graph.Node;
  6. import de.tu_darmstadt.informatik.tk.scopviz.debug.Debug;
  7. /**
  8. * Class extending GraphManager. Offers the possibility to merge an underlay and
  9. * an operator graph.
  10. *
  11. *
  12. * @author Matthias Wilhelm
  13. *
  14. */
  15. public class MappingGraphManager extends GraphManager implements EdgeCreatedListener, NodeCreatedListener {
  16. public static final String UNDERLAY = "underlay";
  17. public static final String OPERATOR = "operator";
  18. public static final String ATTRIBUTE_KEY_PROCESS_NEED = "process-need";
  19. public static final String ATTRIBUTE_KEY_PROCESS_USE = "process-use";
  20. public static final String ATTRIBUTE_KEY_PROCESS_MAX = "process-max";
  21. public static final String ATTRIBUTE_KEY_MAPPING = "mapping";
  22. public static final String ATTRIBUTE_KEY_MAPPING_PARENT = "mapping-parent";
  23. public static final String ATTRIBUTE_KEY_MAPPING_PARENT_ID = "mapping-parent-id";
  24. public static final String UI_CLASS_MAPPING = "mapping";
  25. private static final double UNDERLAYER_MOVE_Y = 0;
  26. private static final double OPERATOR_MOVE_Y = 1.5;
  27. // Variables to keep track of new Nodes in the parent graphs
  28. private boolean underlayNodesChanged = false;
  29. private boolean operatorNodesChanged = false;
  30. // References to the parent graphs
  31. GraphManager underlay, operator;
  32. HashMap<String, String> parentsID;;
  33. /**
  34. * Creates a new manager for an empty graph. there is no need to check for
  35. * unique ID's for nodes and edges.
  36. *
  37. * @param graph
  38. * assumes a empty graph
  39. * @param underlay
  40. * the underlay graph
  41. * @param operator
  42. * the operator graph
  43. */
  44. public MappingGraphManager(MyGraph graph, GraphManager underlay, GraphManager operator) {
  45. super(graph);
  46. underlay.deselect();
  47. operator.deselect();
  48. this.underlay = underlay;
  49. this.operator = operator;
  50. parentsID = new HashMap<>();
  51. parentsID.put(UNDERLAY, underlay.getGraph().getId());
  52. parentsID.put(OPERATOR, operator.getGraph().getId());
  53. Debug.out("Created a new Mapping");
  54. mergeGraph(underlay, UNDERLAY, UNDERLAYER_MOVE_Y);
  55. mergeGraph(operator, OPERATOR, OPERATOR_MOVE_Y);
  56. view.getCamera().resetView();
  57. }
  58. /**
  59. * Adds all nodes and edges of the given graph, adds a prefix to the ID of
  60. * every node and edge and offsets the normalized coordinates in y
  61. * direction.
  62. *
  63. * @param gm
  64. * the graph to be added
  65. * @param idPrefix
  66. * the prefix for the ID of every node and edge
  67. * @param moveY
  68. * the offset of the y coordinate
  69. */
  70. private void mergeGraph(GraphManager gm, String idPrefix, double moveY) {
  71. mergeNodes(gm, idPrefix, moveY);
  72. // TODO: Debug only
  73. int i = 0;
  74. for (Edge edge : gm.getGraph().getEdgeSet()) {
  75. addEdge(edge, idPrefix);
  76. // TODO: Debug only
  77. i++;
  78. }
  79. Debug.out("added " + i + " Edge" + (i == 1 ? "" : "s") + " from \"" + idPrefix + "\"");
  80. }
  81. /**
  82. * Adds all nodes of the given graph, adds a prefix to the ID of every node
  83. * and offsets the normalized coordinates in y direction.
  84. *
  85. * @param gm
  86. * the graph to be added
  87. * @param idPrefix
  88. * the prefix for the ID of every node
  89. * @param moveY
  90. * the offset of the y coordinate
  91. */
  92. private void mergeNodes(GraphManager gm, String idPrefix, double moveY) {
  93. // precalculate scale and offset to normalize x coordinates
  94. double maxX = gm.getMaxX();
  95. double minX = gm.getMinX();
  96. double scaleX = 1 / (maxX - minX);
  97. double addX = -minX * scaleX;
  98. // precalculate scale and offset to normalize y coordinates
  99. double maxY = gm.getMaxY();
  100. double minY = gm.getMinY();
  101. double scaleY = 1 / (maxY - minY);
  102. double addY = -minY * scaleY + moveY;
  103. // TODO: Debug only
  104. int i = 0;
  105. // loops through all nodes, adds them if they don't exist already and
  106. // normalizes their coordinates
  107. for (Node node : gm.getGraph().getNodeSet()) {
  108. // add node if it doesn't exist
  109. Node newNode = getGraph().getNode(idPrefix + node.getId());
  110. if (newNode == null) {
  111. addNode(node, idPrefix);
  112. newNode = getGraph().getNode(idPrefix + node.getId());
  113. // TODO: Debug only
  114. i++;
  115. }
  116. // normalize coordinates
  117. double[] n = Toolkit.nodePosition(node);
  118. double cX = n[0];
  119. double x = cX * scaleX + addX;
  120. double cY = n[1];
  121. double y = cY * scaleY + addY;
  122. newNode.changeAttribute("x", x);
  123. newNode.changeAttribute("y", y);
  124. if (hasClass(newNode, UI_CLASS_PROCESSING_ENABLED))
  125. initCapacity(newNode);
  126. }
  127. Debug.out("added " + i + " Node" + (i == 1 ? "" : "s") + " from \"" + idPrefix + "\"");
  128. }
  129. /**
  130. * Gets invoked by the GraphDisplayManager every time the mapping layer is
  131. * loaded. Checks whether nodes have been added to the parent graphs
  132. */
  133. public void activated() {
  134. if (underlayNodesChanged) {
  135. mergeNodes(underlay, UNDERLAY, UNDERLAYER_MOVE_Y);
  136. underlayNodesChanged = false;
  137. }
  138. if (operatorNodesChanged) {
  139. mergeNodes(operator, OPERATOR, OPERATOR_MOVE_Y);
  140. operatorNodesChanged = false;
  141. }
  142. }
  143. /**
  144. * Checks whether the given graph is underlay or operator graph to this
  145. * object or not.
  146. *
  147. * @param gm
  148. * the graph to check
  149. * @return true if the given graph is underlay or operator graph to this
  150. * graph. false otherwise
  151. */
  152. public boolean hasGraphManagerAsParent(GraphManager gm) {
  153. return (underlay.getGraph().getId().equals(gm.getGraph().getId()))
  154. || (operator.getGraph().getId().equals(gm.getGraph().getId()));
  155. }
  156. /**
  157. * Adds a <b>Copy</b> of the given Edge to the graph. The Copy retains the
  158. * ID and all attributes but adds the ID prefix in front of the all old IDs.
  159. *
  160. * @param e
  161. * the Edge to be added to the graph
  162. * @param idPrefix
  163. * the String to be added as prefix to the ID
  164. */
  165. private void addEdge(Edge e, String idPrefix) {
  166. HashMap<String, Object> attributes = new HashMap<>();
  167. for (String s : e.getAttributeKeySet()) {
  168. attributes.put(s, e.getAttribute(s));
  169. }
  170. attributes.put(ATTRIBUTE_KEY_MAPPING, false);
  171. attributes.put(ATTRIBUTE_KEY_MAPPING_PARENT, idPrefix);
  172. attributes.put(ATTRIBUTE_KEY_MAPPING_PARENT_ID, parentsID.get(idPrefix));
  173. g.addEdge(idPrefix + e.getId(), idPrefix + e.getSourceNode().getId(), idPrefix + e.getTargetNode().getId());
  174. g.getEdge(idPrefix + e.getId()).addAttributes(attributes);
  175. }
  176. @Override
  177. public void addNode(Node n) {
  178. // This function mustn't be called.
  179. Debug.out("Someone called addNode(Node n) with a MappingGraphManager");
  180. }
  181. /**
  182. * Adds a <b>Copy</b> of the given Node to the graph. The Copy retains the
  183. * ID and all attributes but adds the ID prefix in front of the old ID.
  184. *
  185. * @param n
  186. * the Node to be added to the graph
  187. * @param idPrefix
  188. * the String to be added as prefix to the ID
  189. */
  190. private void addNode(Node n, String idPrefix) {
  191. HashMap<String, Object> attributes = new HashMap<>();
  192. for (String s : n.getAttributeKeySet()) {
  193. attributes.put(s, n.getAttribute(s));
  194. }
  195. attributes.put(ATTRIBUTE_KEY_MAPPING_PARENT, idPrefix);
  196. attributes.put(ATTRIBUTE_KEY_MAPPING_PARENT_ID, parentsID.get(idPrefix));
  197. g.addNode(idPrefix + n.getId());
  198. g.getNode(idPrefix + n.getId()).addAttributes(attributes);
  199. }
  200. @Override
  201. public void nodeCreated(Node n, String graphID) {
  202. if (graphID.equals(underlay.getGraph().getId()))
  203. underlayNodesChanged = true;
  204. else if (graphID.equals(operator.getGraph().getId()))
  205. operatorNodesChanged = true;
  206. }
  207. @Override
  208. public void edgeCreated(Edge e, String graphID) {
  209. if (graphID.equals(underlay.getGraph().getId()))
  210. addEdge(e, UNDERLAY);
  211. else if (graphID.equals(operator.getGraph().getId()))
  212. addEdge(e, OPERATOR);
  213. }
  214. @Override
  215. public void createEdges(String id) {
  216. super.createEdges(id);
  217. if (lastClickedID != null) {
  218. Double need = g.getNode(lastClickedID).getAttribute(ATTRIBUTE_KEY_PROCESS_NEED);
  219. if (need != null)
  220. for (Node n : g.getNodeSet())
  221. if (hasClass(n, UI_CLASS_PROCESSING_ENABLED))
  222. showExpectedCapacity(n, need);
  223. } else {
  224. for (Node n : g.getNodeSet())
  225. if (hasClass(n, UI_CLASS_PROCESSING_ENABLED))
  226. showExpectedCapacity(n, 0);
  227. }
  228. }
  229. /**
  230. * checks whether the Node can handle the load first.<br/>
  231. * creates a edge between to nodes
  232. */
  233. @Override
  234. public boolean createEdge(String to, String from) {
  235. Node fromNode = getGraph().getNode(from);
  236. Node toNode = getGraph().getNode(to);
  237. if (fromNode.hasEdgeBetween(to))
  238. return false;
  239. String fromParent = fromNode.getAttribute(ATTRIBUTE_KEY_MAPPING_PARENT);
  240. String toParent = toNode.getAttribute(ATTRIBUTE_KEY_MAPPING_PARENT);
  241. if (fromParent == null || toParent == null)
  242. return false;
  243. if (fromParent.equals(toParent)) {
  244. deselectNodesAfterEdgeCreation(lastClickedID);
  245. lastClickedID = to;
  246. selectNodeForEdgeCreation(lastClickedID);
  247. return false;
  248. }
  249. String newID = Main.getInstance().getUnusedID();
  250. Edge e;
  251. Node underlayNode;
  252. Node operatorNode;
  253. if (fromParent.equals(UNDERLAY)) {
  254. underlayNode = fromNode;
  255. operatorNode = toNode;
  256. } else if (toParent.equals(UNDERLAY)) {
  257. underlayNode = toNode;
  258. operatorNode = fromNode;
  259. } else
  260. return false;
  261. // check if processing enabled node
  262. if (!hasClass(underlayNode, UI_CLASS_PROCESSING_ENABLED))
  263. return false;
  264. // check and update capacity
  265. if (!updatedCapacity(underlayNode, operatorNode))
  266. return false;
  267. e = getGraph().addEdge(newID, operatorNode, underlayNode, true);
  268. Debug.out("Created an directed edge with Id " + newID + " from " + operatorNode + " to " + underlayNode);
  269. e.addAttribute("ui.class", UI_CLASS_MAPPING);
  270. e.addAttribute(ATTRIBUTE_KEY_MAPPING, true);
  271. selectEdge(newID);
  272. return true;
  273. }
  274. private void initCapacity(Node underlayNode) {
  275. Double used = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_USE);
  276. Double max = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_MAX);
  277. if (max == null || max == 0)
  278. return;
  279. if (used == null)
  280. used = new Double(0);
  281. double[] pieValues = { used / max, 0, 1 - used / max };
  282. underlayNode.setAttribute("ui.pie-values", pieValues);
  283. underlayNode.setAttribute(ATTRIBUTE_KEY_PROCESS_USE, used);
  284. }
  285. private boolean updatedCapacity(Node underlayNode, Node operatorNode) {
  286. Double needed = operatorNode.getAttribute(ATTRIBUTE_KEY_PROCESS_NEED);
  287. Double used = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_USE);
  288. Double max = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_MAX);
  289. if (needed == null)
  290. return true;
  291. if (max == null || max == 0)
  292. if (needed > 0)
  293. return false;
  294. else
  295. return true;
  296. if (used == null)
  297. used = new Double(0);
  298. if (used + needed > max)
  299. return false;
  300. used += needed;
  301. double[] pieValues = { used / max, 0, 1 - used / max };
  302. underlayNode.setAttribute("ui.pie-values", pieValues);
  303. underlayNode.setAttribute(ATTRIBUTE_KEY_PROCESS_USE, used);
  304. return true;
  305. }
  306. private void showExpectedCapacity(Node underlayNode, double need) {
  307. Double used = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_USE);
  308. Double max = underlayNode.getAttribute(ATTRIBUTE_KEY_PROCESS_MAX);
  309. if (max == null || max == 0)
  310. return;
  311. if (used == null)
  312. used = new Double(0);
  313. double[] pieValues = { used / max, 0, 1 - used / max, 0 };
  314. if (need + used > max) {
  315. pieValues[3] = pieValues[2];
  316. pieValues[2] = 0;
  317. } else {
  318. pieValues[1] = need / max;
  319. pieValues[2] -= need / max;
  320. }
  321. underlayNode.setAttribute("ui.pie-values", pieValues);
  322. underlayNode.setAttribute(ATTRIBUTE_KEY_PROCESS_USE, used);
  323. }
  324. @Override
  325. public boolean selectNodeForEdgeCreation(String nodeID) {
  326. Node n = g.getNode(nodeID);
  327. String parent = n.getAttribute(ATTRIBUTE_KEY_MAPPING_PARENT);
  328. if (parent == null)
  329. return false;
  330. if (parent.equals(OPERATOR))
  331. return super.selectNodeForEdgeCreation(nodeID);
  332. if (hasClass(n, UI_CLASS_PROCESSING_ENABLED))
  333. return super.selectNodeForEdgeCreation(nodeID);
  334. return false;
  335. }
  336. public void deleteEdge(final String id) {
  337. super.deleteEdge(id);
  338. }
  339. }