1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package name.angoca.zemucan.core.graph.model;
30
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37
38 import name.angoca.zemucan.AbstractZemucanException;
39 import name.angoca.zemucan.ParameterNullException;
40 import name.angoca.zemucan.tools.Constants;
41 import name.angoca.zemucan.tools.configurator.Configurator;
42
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 public class Graph {
93
94
95
96
97 private static final Logger LOGGER = LoggerFactory.getLogger(Graph.class);
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 private static void changeAscendancyNodeRelations(
116 final AbstractGraphNode
117 final AbstractGraphNode
118 assert n1 != null;
119 assert n2 != null;
120 assert node != null;
121 assert n1 != n2;
122 assert n2 != node;
123
124
125 node.removeChild(n2);
126 n2.removeParent(node);
127
128 n1.addParent(node);
129 node.addChild(n1);
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 private static void changeDescendancyNodeRelations(
149 final AbstractGraphNode
150 final AbstractGraphNode
151 assert n1 != null;
152 assert n2 != null;
153 assert node != null;
154 assert n1 != n2;
155 assert n2 != node;
156
157
158 node.addParent(n1);
159
160
161 node.removeParent(n2);
162 n2.removeChild(node);
163
164
165 n1.addChild(node);
166 }
167
168
169
170
171
172
173
174
175
176
177 static boolean checkChildren(final AbstractGraphNode
178 throws AbstractZemucanException {
179 assert node != null;
180
181 boolean ret = false;
182
183 if (node.getChildren().size() > 1) {
184 Graph.LOGGER.debug("Fusioning children in {}", node.getId());
185
186 final List<AbstractGraphNode> children = new ArrayList<AbstractGraphNode>();
187 children.addAll(node.getChildren());
188 Collections.sort(children);
189 AbstractGraphNode n1 = children.get(0);
190 Graph.LOGGER.debug("Analyzing to fusion: {}", n1.getId());
191
192
193 for (int i = 1; i < children.size(); i += 1) {
194 final AbstractGraphNode n2 = children.get(i);
195 if ((n2 != null)
196 && (n1 instanceof TextualGraphNode)
197 && (n2 instanceof TextualGraphNode)
198 && ((TextualGraphNode) n1).getName().equals(
199 ((TextualGraphNode) n2).getName())) {
200
201 Graph.LOGGER.debug("Fusionning nodes {} and {}",
202 n1.getId(), n2.getId());
203 Graph.nodeFusion(n1, n2);
204 ret = true;
205 } else if (n2 != null) {
206
207 n1 = n2;
208 } else {
209
210 assert false;
211 }
212 }
213 } else {
214 Graph.LOGGER.debug("No children to fusion in {}", node.getId());
215 }
216 return ret;
217 }
218
219
220
221
222
223
224
225
226 private static void goBackward(final AbstractGraphNode
227 assert node != null;
228
229 if (!node.isGoToEndingNode()) {
230 node.setGoToEndingNode(true);
231 final List<AbstractGraphNode> parents = node.getParents();
232 for (final AbstractGraphNode graphNode : parents) {
233 Graph.goBackward(graphNode);
234 }
235 }
236 }
237
238
239
240
241
242
243
244
245 private static void goForward(final AbstractGraphNode
246 assert node != null;
247
248 if (!node.isComeFromStartingNode()) {
249 node.setComeFromStartingNode(true);
250 final List<AbstractGraphNode> children = node.getChildren();
251 for (final AbstractGraphNode graphNode : children) {
252 Graph.goForward(graphNode);
253 }
254 }
255 }
256
257
258
259
260
261
262
263
264
265
266
267
268
269 static void nodeFusion(final AbstractGraphNode
270 final AbstractGraphNode
271 throws AbstractZemucanException {
272 assert n1 != null;
273 assert n2 != null;
274 assert n1 != n2;
275
276
277 while (n2.getChildren().size() >= 1) {
278 final AbstractGraphNode node = n2.getChildren().get(0);
279 Graph.changeDescendancyNodeRelations(n1, n2, node);
280 }
281
282 while (n2.getParents().size() >= 1) {
283 final AbstractGraphNode node = n2.getParents().get(0);
284 Graph.changeAscendancyNodeRelations(n1, n2, node);
285 }
286 }
287
288
289
290
291 private EndingNode endingNode;
292
293
294
295
296 private final boolean extraNodes;
297
298
299
300
301
302
303 private GraphState graphState;
304
305
306
307
308
309 private String name;
310
311
312
313
314
315 private Map<String, AbstractGraphNode> nodes;
316
317
318
319
320 private StartingNode startingNode;
321
322
323
324
325
326
327
328
329
330
331
332
333
334 public Graph(final String
335 throws ParameterNullException {
336 if (graphName == null) {
337 throw new ParameterNullException("name");
338 }
339
340 this.name = graphName;
341
342 this.nodes = new HashMap<String, AbstractGraphNode>();
343 this.graphState = GraphState.FirstPhase;
344
345 this.extraNodes = addExtraNodes;
346
347 Graph.LOGGER.info("'{}' graph started.", graphName);
348 }
349
350
351
352
353
354
355
356
357 private void addExtraNodes() throws AbstractGraphException {
358 if ((this.startingNode != null) && (this.endingNode != null)) {
359
360 final GraphNode aboutCaller;
361 final String aboutNode = Configurator.getInstance().getProperty(
362 Constants.ABOUT_TOKEN_PROPERTY);
363 if (aboutNode == null) {
364 aboutCaller = new GraphNode(Constants.ABOUT_TOKEN_ID,
365 Constants.ABOUT_TOKEN_VALUE, this);
366 } else {
367 aboutCaller = new GraphNode(Constants.ABOUT_TOKEN_ID,
368 aboutNode, this);
369 }
370 final AboutNode about = new AboutNode(this);
371
372
373 this.nodes.put(this.name + ':' + Constants.ABOUT_TOKEN_ID,
374 aboutCaller);
375 this.nodes.put(this.name + ':' + Constants.ABOUT_CONTENT_TOKEN_ID,
376 about);
377
378
379 this.startingNode.addChild(aboutCaller);
380 aboutCaller.addParent(this.startingNode);
381 aboutCaller.addChild(about);
382 about.addParent(aboutCaller);
383 about.addChild(this.endingNode);
384 this.endingNode.addParent(about);
385
386
387 final GraphNode helpCaller;
388 final String helpNode = Configurator.getInstance().getProperty(
389 Constants.HELP_TOKEN_PROPERTY);
390 if (helpNode == null) {
391 helpCaller = new GraphNode(Constants.HELP_TOKEN_ID,
392 Constants.HELP_TOKEN_VALUE, this);
393 } else {
394 helpCaller = new GraphNode(Constants.HELP_TOKEN_ID, helpNode,
395 this);
396 }
397 final HelpNode help = new HelpNode(this);
398
399
400 this.nodes.put(this.name + ':' + Constants.HELP_TOKEN_ID,
401 helpCaller);
402 this.nodes.put(this.name + ':' + Constants.HELP_CONTENT_TOKEN_ID,
403 help);
404
405
406 this.startingNode.addChild(helpCaller);
407 helpCaller.addParent(this.startingNode);
408 helpCaller.addChild(help);
409 help.addParent(helpCaller);
410 help.addChild(this.endingNode);
411 this.endingNode.addParent(help);
412
413
414 final GraphNode licenseCaller;
415 final String licenseNode = Configurator.getInstance().getProperty(
416 Constants.LICENSE_TOKEN_PROPERTY);
417 if (licenseNode == null) {
418 licenseCaller = new GraphNode(Constants.LICENSE_TOKEN_ID,
419 Constants.LICENSE_TOKEN_VALUE, this);
420 } else {
421 licenseCaller = new GraphNode(Constants.LICENSE_TOKEN_ID,
422 licenseNode, this);
423 }
424 final LicenseNode license = new LicenseNode(this);
425
426
427 this.nodes.put(this.name + ':' + Constants.LICENSE_TOKEN_ID,
428 licenseCaller);
429 this.nodes.put(
430 this.name + ':' + Constants.LICENSE_CONTENT_TOKEN_ID,
431 license);
432
433
434 this.startingNode.addChild(licenseCaller);
435 licenseCaller.addParent(this.startingNode);
436 licenseCaller.addChild(license);
437 license.addParent(licenseCaller);
438 license.addChild(this.endingNode);
439 this.endingNode.addParent(license);
440 } else {
441 Graph.LOGGER
442 .info("Extra nodes could not be added, there were not " +
443 "StartingNode or EndingNode.");
444 }
445 }
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462 public final AbstractGraphNode addNode(final String
463 final String
464 throws AbstractGraphException {
465 if (!this.graphState.equals(GraphState.FirstPhase)) {
466 throw new InvalidGraphStateException(this.graphState,
467 GraphState.FirstPhase);
468 }
469
470 Graph.LOGGER.debug("Adding node '{}' ({}, {}) in '{}' graph",
471 new String[] { nodeId, nodeName, Boolean.toString(reserved),
472 this.name });
473
474
475 AbstractGraphNode node = null;
476
477 if (nodeId.equals(Constants.STARTING_NODE)) {
478 if (nodeName.equals(Constants.STARTING_NODE) && reserved) {
479
480 node = new StartingNode(this);
481 this.startingNode = (StartingNode) node;
482 } else {
483 throw new InvalidStartingNodeException();
484 }
485 } else if (nodeId.equals(Constants.ENDING_NODE)) {
486 if (nodeName.equals(Constants.ENDING_NODE) && reserved) {
487
488 node = new EndingNode(this);
489 this.endingNode = (EndingNode) node;
490 } else {
491 throw new InvalidEndingNodeException();
492 }
493 } else if (nodeId.startsWith(Constants.NEXT_NODE) && reserved) {
494
495 node = new NextNode(nodeName, this);
496 } else {
497
498 if (reserved) {
499 node = new GraphNode(nodeId, nodeName, this);
500 } else {
501 node = new NonReservedGraphNode(nodeId, nodeName, this);
502 }
503
504 }
505
506
507 if (this.nodes.containsKey(this.name + ':' + nodeId)) {
508 throw new DuplicatedNodeException(nodeId);
509 }
510 this.nodes.put(this.name + ':' + nodeId, node);
511
512 Graph.LOGGER.debug("Addition {}", this);
513
514 assert node != null;
515
516 return node;
517 }
518
519
520
521
522
523
524
525
526
527
528
529
530 public void addRelation(final AbstractGraphNode parentNode,
531 final AbstractGraphNode childNode)
532 throws AbstractZemucanException {
533 final int size = this.name.length() + 1;
534 String parentId = parentNode.getId();
535 String childId = childNode.getId();
536 if (parentId.startsWith(this.name)) {
537 parentId = parentId.substring(size);
538 }
539 if (childId.startsWith(this.name)) {
540 childId = childId.substring(size);
541 }
542 this.addRelation(parentId, childId);
543 Graph.LOGGER.debug("Relation {}", parentNode);
544 }
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560 public final void addRelation(final String
561 final String
562 Graph.LOGGER.debug(
563 "Adding relation in graph '{}' between '{}' and '{}'",
564 new String[] { this.name, parentId, childId });
565
566 if (parentId == null) {
567 throw new ParameterNullException("parentId");
568 }
569 if (childId == null) {
570 throw new ParameterNullException("childId");
571 }
572 if (this.graphState.equals(GraphState.FirstPhase)) {
573 throw new InvalidGraphStateException(this.graphState,
574 GraphState.SecondPhase);
575 }
576 if (this.graphState.equals(GraphState.Validated)) {
577 this.graphState = GraphState.SecondPhase;
578 }
579
580 final String key = this.name + ':' + parentId;
581 final AbstractGraphNode parent = this.nodes.get(key);
582 if (parent == null) {
583 throw new NotExistingNodeException(parentId);
584 }
585
586
587 final AbstractGraphNode childNode = this.nodes.get(this.name + ':'
588 + childId);
589 if (childNode == null) {
590 throw new NotExistingChildNodeException(parentId, childId);
591 }
592
593 parent.addChild(childNode);
594 childNode.addParent(parent);
595 }
596
597
598
599
600
601
602
603
604 public final void checkDuplicates() throws DuplicatedNodeNameException {
605 final Iterator<AbstractGraphNode> it = this.nodes.values().iterator();
606 while (it.hasNext()) {
607 final AbstractGraphNode node = it.next();
608 final int size = node.getChildren().size();
609 if (size >= 2) {
610 final List<AbstractGraphNode> children = new ArrayList<AbstractGraphNode>();
611 children.addAll(node.getChildren());
612 Collections.sort(children);
613 AbstractGraphNode n0 = children.get(0);
614 for (int i = 1; i < size; i += 1) {
615 final AbstractGraphNode n1 = children.get(i);
616 if ((n0 instanceof TextualGraphNode)
617 && (n1 instanceof TextualGraphNode)) {
618 final TextualGraphNode textualn0 = (TextualGraphNode) n0;
619 final TextualGraphNode textualn1 = (TextualGraphNode) n1;
620 if (textualn0.getName().equals(textualn1.getName())) {
621 throw new DuplicatedNodeNameException(node.getId(),
622 textualn0.getName(), n0.getId(), n1.getId());
623 }
624 }
625 n0 = n1;
626 }
627 }
628 }
629 }
630
631
632
633
634
635
636
637
638
639
640 private boolean checkNoParentsForStartingNode()
641 throws AbstractZemucanException {
642 for (final AbstractGraphNode node : this.nodes.values()) {
643
644 final List<AbstractGraphNode> ways = node.getChildren();
645 for (final AbstractGraphNode graphNode : ways) {
646 if (graphNode instanceof StartingNode) {
647
648
649 throw new ReferencingStartingNodeException(node.getId());
650 }
651 }
652
653
654 final List<AbstractGraphNode> parents = node.getParents();
655 for (final AbstractGraphNode graphNode : parents) {
656 if (graphNode instanceof EndingNode) {
657
658
659 throw new ReferencingEndingNodeException(node.getId());
660 }
661 }
662 }
663 return true;
664 }
665
666
667
668
669
670 @Override
671 public final boolean equals(final Object obj) {
672 boolean result = false;
673 if (obj instanceof Graph) {
674 final Graph graph = (Graph) obj;
675 if (this.name.equals(graph.name)
676 && (this.extraNodes == graph.extraNodes)
677 && (this.graphState == graph.graphState)
678 && (this.startingNode != null)
679 && (graph.startingNode != null)
680 && this.startingNode.equals(graph.startingNode)
681 && (this.endingNode != null) && (graph.endingNode != null)
682 && this.endingNode.equals(graph.endingNode)
683 && (this.nodes.size() == graph.nodes.size())) {
684 result = true;
685 for (final String key : this.nodes.keySet()) {
686 final AbstractGraphNode node = graph.nodes.get(key);
687 if (!this.exist(key, node)) {
688 result = false;
689 }
690 }
691 }
692 }
693 return result;
694 }
695
696
697
698
699
700
701
702
703
704
705 private boolean exist(final String
706 final AbstractGraphNode
707 assert key != null;
708 assert !key.equals("");
709
710 boolean result = false;
711 final AbstractGraphNode graphNode = this.nodes.get(key);
712 if ((graphNode != null) && graphNode.equals(node)) {
713 result = true;
714 }
715 return result;
716 }
717
718
719
720
721
722
723
724
725
726
727 public final void firstPhaseFinished() throws AbstractZemucanException {
728 if (!this.graphState.equals(GraphState.FirstPhase)) {
729 throw new InvalidGraphStateException(this.graphState,
730 GraphState.FirstPhase);
731 }
732
733
734 if (this.extraNodes) {
735 this.addExtraNodes();
736 }
737
738 this.graphState = GraphState.SecondPhase;
739
740 Graph.LOGGER.info("'{}' - First Phase finished.", this.name);
741 }
742
743
744
745
746
747
748
749
750
751 final EndingNode
752 if (!this.graphState.equals(GraphState.Validated)) {
753 throw new InvalidGraphStateException(this.graphState,
754 GraphState.Validated);
755 }
756 return this.endingNode;
757 }
758
759
760
761
762
763
764 final GraphState
765 return this.graphState;
766 }
767
768
769
770
771
772
773 public final String
774 return this.name;
775 }
776
777
778
779
780
781
782 final Map<String, AbstractGraphNode>
783 return this.nodes;
784 }
785
786
787
788
789
790
791
792
793
794 public final StartingNode getStartingNode()
795 throws InvalidGraphStateException {
796 if (!this.graphState.equals(GraphState.Validated)) {
797 throw new InvalidGraphStateException(this.graphState,
798 GraphState.Validated);
799 }
800 return this.startingNode;
801 }
802
803
804
805
806
807 @Override
808 public final int hashCode() {
809 int result = this.name.hashCode() - GraphState.FirstPhase.hashCode();
810 if (this.extraNodes) {
811 result *= 2;
812 }
813 if (this.startingNode != null) {
814 result -= this.startingNode.hashCode();
815 } else {
816 result += 1;
817 }
818 if (this.endingNode != null) {
819 result -= this.endingNode.hashCode();
820 } else {
821 result += 2;
822 }
823 if (this.nodes.size() != 0) {
824 result /= this.nodes.size();
825 }
826
827 return result;
828 }
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843 public final void merge(final Graph graph)
844 throws AbstractZemucanException {
845 assert graph != this;
846 assert !this.name.equals(graph.name);
847 assert this.graphState == GraphState.Validated;
848 assert graph.graphState == GraphState.Validated;
849
850
851 Graph.nodeFusion(graph.startingNode, this.startingNode);
852 this.nodes.remove(this.startingNode.getId());
853 Graph.nodeFusion(graph.endingNode, this.endingNode);
854 this.nodes.remove(this.endingNode.getId());
855
856
857 Object[] keys = this.nodes.keySet().toArray();
858 int i = 0;
859 int len = keys.length;
860 while (i < len) {
861 final String id = (String) keys[i];
862 AbstractGraphNode node = this.nodes.remove(id);
863 graph.nodes.put(id, node);
864 i += 1;
865 }
866
867 graph.name = "merged:{" + graph.name + ',' + this.name + '}';
868
869
870 final Map<String, AbstractGraphNode> newNodes = new HashMap<String, AbstractGraphNode>();
871 keys = graph.nodes.keySet().toArray();
872 i = 0;
873 len = keys.length;
874 while (i < len) {
875 final String id = (String) keys[i];
876 AbstractGraphNode node = graph.nodes.remove(id);
877 node.addGraphName(graph.name);
878 newNodes.put(node.getId(), node);
879 i += 1;
880 }
881 graph.nodes = newNodes;
882 }
883
884
885
886
887
888
889
890
891
892
893
894
895 public void removeRelation(final AbstractGraphNode parentNode,
896 final AbstractGraphNode childNode)
897 throws AbstractZemucanException {
898 final int size = this.name.length() + 1;
899 String parentId = parentNode.getId();
900 String childId = childNode.getId();
901 if (parentId.startsWith(this.name)) {
902 parentId = parentId.substring(size);
903 }
904 if (childId.startsWith(this.name)) {
905 childId = childId.substring(size);
906 }
907 this.removeRelation(parentId, childId);
908 Graph.LOGGER.debug("Relation {}", parentNode);
909 }
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925 private void removeRelation(final String parentId, final String childId)
926 throws AbstractZemucanException {
927 Graph.LOGGER.debug(
928 "Removing relation in graph '{}' between '{}' and '{}'",
929 new String[] { this.name, parentId, childId });
930
931 if (parentId == null) {
932 throw new ParameterNullException("parentId");
933 }
934 if (childId == null) {
935 throw new ParameterNullException("childId");
936 }
937 if (this.graphState.equals(GraphState.FirstPhase)) {
938 throw new InvalidGraphStateException(this.graphState,
939 GraphState.SecondPhase);
940 }
941 if (this.graphState.equals(GraphState.Validated)) {
942 this.graphState = GraphState.SecondPhase;
943 }
944
945 final AbstractGraphNode parent = this.nodes.get(this.name + ':'
946 + parentId);
947 if (parent == null) {
948 throw new NotExistingNodeException(parentId);
949 }
950
951
952 final AbstractGraphNode childNode = this.nodes.get(this.name + ':'
953 + childId);
954 if (childNode == null) {
955 throw new NotExistingChildNodeException(parentId, childId);
956 }
957
958 parent.removeChild(childNode);
959 childNode.removeParent(parent);
960 }
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979 public final StartingNode
980 throws AbstractZemucanException {
981 if (this.graphState.equals(GraphState.FirstPhase)) {
982 throw new InvalidGraphStateException(this.graphState,
983 GraphState.SecondPhase);
984 }
985
986
987 for (final AbstractGraphNode node : this.nodes.values()) {
988 node.setComeFromStartingNode(false);
989 node.setGoToEndingNode(false);
990 }
991
992 assert this.checkNoParentsForStartingNode();
993
994 if (this.startingNode == null) {
995 throw new StartingNodeNotDefinedException();
996 }
997 Graph.goForward(this.startingNode);
998
999 if (this.endingNode == null) {
1000 throw new EndingNodeNotDefinedException();
1001 }
1002 Graph.goBackward(this.endingNode);
1003
1004 for (final AbstractGraphNode node : this.nodes.values()) {
1005 if (!node.isComeFromStartingNode()) {
1006 throw new NodeNotComesFromStartingNodeException(node.getId());
1007 } else if (!node.isGoToEndingNode()) {
1008 throw new NodeNotGoesToEndingNodeException(node.getId());
1009 }
1010 }
1011
1012 this.checkDuplicates();
1013
1014 if ((this.startingNode.getChildren().size() == 1)
1015 && this.startingNode.getChildren().get(0) instanceof EndingNode) {
1016 throw new EmptyGrammarException();
1017 }
1018
1019 Graph.LOGGER.info("'{}' - Second phase finished.", this.name);
1020
1021 this.graphState = GraphState.Validated;
1022
1023 assert this.startingNode != null;
1024 return this.startingNode;
1025 }
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035 public final void simplifyGraph() throws AbstractZemucanException {
1036 Graph.LOGGER.debug("-> Simplyfing graph");
1037
1038
1039 Graph.LOGGER.debug("-> Remplacing next nodes");
1040 Iterator<AbstractGraphNode> ite = this.nodes.values().iterator();
1041 while (ite.hasNext()) {
1042 final AbstractGraphNode parentNode = ite.next();
1043 Graph.LOGGER.debug("parent {}", parentNode.getId());
1044 final List<AbstractGraphNode> children = parentNode.getChildren();
1045
1046 if (!(parentNode instanceof EndingNode) && children.size() == 0) {
1047
1048 throw new RuntimeException("Node without children.");
1049 }
1050 int size = children.size();
1051 for (int i = 0; i < size; i++) {
1052 final AbstractGraphNode childNode = children.get(i);
1053 Graph.LOGGER.debug("child {}", childNode.getId());
1054 if (childNode instanceof NextNode) {
1055 final List<AbstractGraphNode> grandChildren = childNode
1056 .getChildren();
1057
1058 for (int j = 0; j < grandChildren.size(); j++) {
1059 final AbstractGraphNode grandChildNode = grandChildren
1060 .get(j);
1061 this.addRelation(parentNode, grandChildNode);
1062 this.removeRelation(parentNode, childNode);
1063 }
1064
1065 ite = this.nodes.values().iterator();
1066 i = children.size();
1067 Graph.LOGGER.debug("Restarted");
1068 }
1069 }
1070 }
1071
1072 Graph.LOGGER.debug("-> Removing next nodes and their iterations");
1073 final Object[] set = this.nodes.keySet().toArray();
1074 for (int i = 0; i < set.length; i++) {
1075 final String key = (String) set[i];
1076 final AbstractGraphNode node = this.nodes.get(key);
1077 if (node instanceof NextNode) {
1078 final List<AbstractGraphNode> children = node.getChildren();
1079 for (int j = 0; j < children.size(); j++) {
1080 final AbstractGraphNode childNode = children.get(j);
1081 this.removeRelation(node, childNode);
1082 }
1083 this.nodes.remove(key);
1084 }
1085 }
1086
1087
1088 Graph.LOGGER.debug("-> Fusionning common nodes");
1089 Iterator<AbstractGraphNode> it = this.nodes.values().iterator();
1090 while (it.hasNext()) {
1091 final AbstractGraphNode node = it.next();
1092 if (Graph.checkChildren(node)) {
1093
1094 it = this.nodes.values().iterator();
1095 }
1096 }
1097
1098
1099 Graph.LOGGER.debug("-> Removing empty nodes");
1100 final Object[] keys = this.nodes.keySet().toArray();
1101 for (final Object key2 : keys) {
1102 final String key = (String) key2;
1103
1104 final AbstractGraphNode node = this.nodes.get(key);
1105
1106 int childrenSize = node.getChildren().size();
1107 int parentsSize = node.getParents().size();
1108 Graph.LOGGER.debug("node {}, parents {} children {}", new Object[] {
1109 node.getId(), parentsSize, childrenSize });
1110 if ((childrenSize == 0) && (parentsSize == 0)) {
1111 this.nodes.remove(key);
1112 }
1113 }
1114 }
1115
1116
1117
1118
1119
1120 @Override
1121 public final String toString() {
1122 String res = this.name + ":[" + this.graphState + '-';
1123 if (this.extraNodes) {
1124 res += "WithExtraNodes";
1125 } else {
1126 res += "WithoutExtraNodes";
1127 }
1128 res += "{" + this.startingNode + '-' + this.endingNode
1129 + "}(" + this.nodes.size() + ":\n";
1130 final List<String> children = new ArrayList<String>();
1131 children.addAll(this.nodes.keySet());
1132 Collections.sort(children);
1133 for (int i = 0; i < children.size(); i++) {
1134 final String key = children.get(i);
1135 final AbstractGraphNode node = this.nodes.get(key);
1136 String nodeString;
1137 if (node instanceof TextualGraphNode) {
1138 nodeString = key + '-'
1139 + ((TextualGraphNode) this.nodes.get(key)).getName()
1140 + '\n';
1141 } else {
1142
1143 nodeString = key + '-' + this.nodes.get(key).getId() + '\n';
1144 }
1145 res += nodeString;
1146 }
1147 res += ')';
1148 res += ']';
1149 return res;
1150 }
1151 }