]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.interop.mapping/src/org/simantics/interop/mapping/data/GraphNode.java
Replace log4j with slf4j
[simantics/interop.git] / org.simantics.interop.mapping / src / org / simantics / interop / mapping / data / GraphNode.java
1 package org.simantics.interop.mapping.data;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.Collection;\r
5 import java.util.HashSet;\r
6 import java.util.List;\r
7 import java.util.Set;\r
8 \r
9 import org.simantics.utils.datastructures.hints.HintContext;\r
10 import org.slf4j.Logger;\r
11 \r
12 \r
13 /**\r
14  * \r
15  * \r
16  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
17  *\r
18  * @param <T>\r
19  */\r
20 public class GraphNode<T> extends HintContext {\r
21         \r
22         private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(GraphNode.class);\r
23         \r
24         protected T data;\r
25         private List<Link<T>> nodes = new ArrayList<Link<T>>();\r
26 \r
27         private boolean disposed = false;\r
28         \r
29         public GraphNode(T data) {\r
30                 this.data = data;\r
31         }\r
32         \r
33         /**\r
34          * Returns data.\r
35          * @return\r
36          */\r
37         public T getData() {\r
38                 return data;\r
39         }\r
40 \r
41         \r
42         @Override\r
43     public void setHint(Key key, Object value) {\r
44                 _checkDisposed();\r
45                 if (value == null)\r
46                         return; \r
47                 super.setHint(key, value);\r
48         }\r
49         \r
50         \r
51         \r
52         \r
53         /**\r
54          * Adds link to the other node.\r
55          * @param relationName name of the link from this node to the other node.\r
56          * @param inverseRelationName nam,e of the link from the other node to this node.\r
57          * @param node the other node.\r
58          * @return the created link. Returns null if the link cannot be created.\r
59          */\r
60         public Link<T> addLink(String relationName, String inverseRelationName,GraphNode<T> node) {\r
61                 _checkDisposed();\r
62                 LOGGER.info("Node link " + data + " " + node.data + " " + relationName + " " + inverseRelationName +"\n");\r
63                 if(containsLink(relationName, node) && node.containsLink(inverseRelationName, this)) {\r
64                         LOGGER.warn("Node " + getData() + " has already given child " +  node.getData() + " ,with name " + relationName + " / " + inverseRelationName);\r
65                         return null;\r
66                 }\r
67                 Link<T> rel = _addLink(relationName,node);\r
68                 Link<T> inv = node._addLink(inverseRelationName,this);\r
69                 rel.setInverseLink(inv);\r
70                 inv.setMainLink(rel);\r
71                 return rel;\r
72         }\r
73         \r
74         /**\r
75          * Adds link to the other node, with <pre>null</pre> link name from the other node to this node.\r
76          * @param relationName\r
77          * @param node name of the link from this node to the other node\r
78          * @return the created link. Returns null if the link cannot be created.\r
79          */\r
80         public Link<T> addLink(String relationName,GraphNode<T> node) {\r
81                 _checkDisposed();\r
82                 if(containsLink(relationName, node)) {\r
83                         LOGGER.warn("Node " + getData() + " has already given child " +  node.getData() + " ,with name " + relationName );\r
84                         return null;\r
85                 }\r
86                 Link<T> rel = _addLink(relationName,node);\r
87                 Link<T> inv = node._addLink(null,this);\r
88                 rel.setInverseLink(inv);\r
89                 inv.setMainLink(rel);\r
90                 return rel;\r
91         }\r
92         \r
93         /**\r
94          * Adds link to the other node, with copying link properties from given link.\r
95          * @param link\r
96          * @param node name of the link from this node to the other node\r
97          * @return the created link. Returns null if the link cannot be created.\r
98          */\r
99         public Link<T> addLink(Link<T> link ,GraphNode<T> node) {\r
100                 _checkDisposed();\r
101                 if(containsLink(link.getName(), node) && node.containsLink(link.getInverseName(), this)) {\r
102                         LOGGER.warn("Node " + getData() + " has already given child " +  node.getData() + " ,with name " + link.getName() + " / " + link.getInverseName());\r
103                         return null;\r
104                 }\r
105                 Link<T> rel = _addLink(link.getName(),node);\r
106                 Link<T> inv = node._addLink(link.getInverseName(),this);\r
107                 rel.setInverseLink(inv);\r
108                 inv.setMainLink(rel);\r
109                 rel.setHints(link.getHints());\r
110                 inv.setHints(link.getInverse().getHints());\r
111                 return rel;\r
112         }\r
113         \r
114         protected Link<T> _addLink(String relation,  GraphNode<T> node) {\r
115                 Link<T> link = new Link<T>(this, relation,node);\r
116                 nodes.add(link);\r
117                 return link;\r
118         }\r
119         \r
120         protected Link<T> _removeLink(String relation,String inverse, GraphNode<T> node) {\r
121                 for (int i = 0; i < nodes.size(); i++) {\r
122                         Link<T> link = nodes.get(i);\r
123                         if (node.equals(link.to()) && equals(relation,link.getName()) && equals(inverse,link.getInverseName())) {\r
124                                 return nodes.remove(i);\r
125                         }\r
126                 }\r
127                 return null;\r
128         }\r
129         \r
130         protected Link<T> _removeLink(String relation) {\r
131                 for (int i = 0; i < nodes.size(); i++) {\r
132                         Link<T> link = nodes.get(i);\r
133                         if (equals(relation,link.getName())) {\r
134                                 return nodes.remove(i);\r
135                         }\r
136                 }\r
137                 return null;\r
138         }\r
139         \r
140         protected Link<T> _removeLink(String relation, String inverse) {\r
141                 for (int i = 0; i < nodes.size(); i++) {\r
142                         Link<T> link = nodes.get(i);\r
143                         if (equals(relation,link.getName()) && equals(inverse,link.getInverseName())) {\r
144                                 return nodes.remove(i);\r
145                         }\r
146                 }\r
147                 return null;\r
148         }\r
149         \r
150         protected Link<T> _removeLink(String relation, GraphNode<T> node) {\r
151                 for (int i = 0; i < nodes.size(); i++) {\r
152                         Link<T> link = nodes.get(i);\r
153                         if (node.equals(link.to()) && equals(relation,link.getName())) {\r
154                                 return nodes.remove(i);\r
155                         }\r
156                 }\r
157                 return null;\r
158         }\r
159         \r
160         protected Link<T> _removeLink(GraphNode<T> node) {\r
161                 for (int i = 0; i < nodes.size(); i++ ) {\r
162                         Link<T> link = nodes.get(i);\r
163                         if (node.equals(link.to())) {\r
164                                 return nodes.remove(i);\r
165                         }\r
166                 }\r
167                 return null;\r
168         }\r
169         \r
170         protected boolean _removeLink(Link<T> link) {\r
171                 return nodes.remove(link);\r
172         }\r
173         \r
174         /**\r
175          * Removes the given link.\r
176          * @param link\r
177          * @return true if the link was removed.\r
178          */\r
179         public boolean removeLink(Link<T> link) {\r
180                 _checkDisposed();\r
181                 if (_removeLink(link)) {\r
182                         if (link.hasInverse()) {\r
183                                 link.to()._removeLink(link.getInverse());\r
184                         }\r
185                         return true;\r
186                 }\r
187                 return false;\r
188         }\r
189         \r
190         /**\r
191          * Removes a link (or multiple links).\r
192          * @param relation the name of the link from this node.\r
193          * @return true if a link was removed.\r
194          */\r
195         public boolean removeLink(String relation) {\r
196                 _checkDisposed();\r
197                 boolean deleted = false;\r
198                 while (true) {\r
199                         Link<T> removed = _removeLink(relation);\r
200                         if (removed == null)\r
201                                 break;\r
202                         if (removed.hasInverse()) {\r
203                                 removed.to()._removeLink(removed.getInverse());\r
204                                 deleted = true;\r
205                         }\r
206                 }\r
207                 return deleted;\r
208         }\r
209         \r
210         /**\r
211          * Removes a link (or multiple links).\r
212          * @param relation the name of the link from this node.\r
213          * @return true if the link was removed.\r
214          */\r
215         public boolean removeLink(String relation, String inverse) {\r
216                 _checkDisposed();\r
217                 boolean deleted = false;\r
218                 while (true) {\r
219                         Link<T> removed = _removeLink(relation, inverse);\r
220                         if (removed == null)\r
221                                 break;\r
222                         if (removed.hasInverse()) {\r
223                                 removed.to()._removeLink(removed.getInverse());\r
224                                 deleted = true;\r
225                         }\r
226                 }\r
227                 return deleted;\r
228         }\r
229 \r
230         /**\r
231          * Removes a link.\r
232          * @param relation the name of the link from this node to the other node.\r
233          * @param node the other node.\r
234          * @return true if the link was removed.\r
235          */\r
236         public boolean removeLink(String relation, GraphNode<T> node) {\r
237                 _checkDisposed();\r
238                 \r
239                 boolean deleted = false;\r
240                 while (true) {\r
241                         Link<T> removed = _removeLink(relation, node);\r
242                         if (removed == null)\r
243                                 break;\r
244                         if (removed.hasInverse()) {\r
245                                 removed.to()._removeLink(removed.getInverse());\r
246                                 deleted = true;\r
247                         }\r
248                 }\r
249                 return deleted;\r
250         }\r
251         \r
252         /**\r
253          * Removes all links from this node to the other node.\r
254          * @param node the other node.\r
255          * @return\r
256          */\r
257         public boolean removeLink(GraphNode<T> node) {\r
258                 _checkDisposed();\r
259                 boolean deleted = false;\r
260                 while (true) {\r
261                         Link<T> removed = _removeLink(node);\r
262                         if (removed == null)\r
263                                 break;\r
264                         if (removed.hasInverse()) {\r
265                                 removed.to()._removeLink(removed.getInverse());\r
266                                 deleted = true;\r
267                         }\r
268                 }\r
269                 return deleted;\r
270         }\r
271         \r
272         /**\r
273          * Removes a link.\r
274          * @param relation the name of the link from this node to the other node.\r
275          * @param inverse the name of the link from the other node to this node.\r
276          * @param node the other node.\r
277          * @return true if the link was removed.\r
278          */\r
279         public boolean removeLink(String relation, String inverse, GraphNode<T> node) {\r
280                 _checkDisposed();\r
281                 Link<T> removed = _removeLink(relation, inverse, node);\r
282                 if (removed != null && removed.hasInverse()) {\r
283                         removed.to()._removeLink(removed.getInverse());\r
284                         return true;\r
285                 }\r
286                 return false;\r
287         }\r
288         \r
289         public boolean containsLink(GraphNode<T> node) {\r
290                 _checkDisposed();\r
291                 for (Link<T> link : nodes) {\r
292                         if (node.equals(link.to()))\r
293                                 return true;\r
294                 }\r
295                 return false;\r
296         }\r
297         \r
298         public boolean containsLink(String relationName, GraphNode<T> node) {\r
299                 _checkDisposed();\r
300                 if (relationName == null)\r
301                         return false;\r
302                 for (Link<T> link : nodes) {\r
303                         if (node.equals(link.to()) && equals(relationName,link.getName()))\r
304                                 return true;\r
305                 }\r
306                 return false;\r
307         }\r
308         \r
309         public boolean containsLink(String relationName, String inverseName, GraphNode<T> node) {\r
310                 _checkDisposed();\r
311                 for (Link<T> link : nodes) {\r
312                         if (node.equals(link.to()) && equals(relationName,link.getName()) && equals(inverseName,link.getInverseName()))\r
313                                 return true;\r
314                 }\r
315                 return false;\r
316         }\r
317 \r
318         public Collection<Link<T>> getLinks() {\r
319                 _checkDisposed();\r
320                 Collection<Link<T>> coll = new ArrayList<Link<T>>(nodes);\r
321                 return coll;\r
322         }\r
323         \r
324         public Collection<GraphNode<T>> getNodes(String rel) {\r
325                 _checkDisposed();\r
326                 Collection<GraphNode<T>> result = new ArrayList<GraphNode<T>>();\r
327 \r
328                 for (Link<T> link : nodes) {\r
329                         if (equals(rel,link.getName()))\r
330                                 result.add(link.to());\r
331                 }\r
332                 \r
333                 return result;\r
334         }\r
335         \r
336         public Collection<Link<T>> getLinks(String rel) {\r
337                 _checkDisposed();\r
338                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
339 \r
340                 for (Link<T> link : nodes) {\r
341                         if (equals(rel,link.getName()))\r
342                                 result.add(link);\r
343                 }\r
344                 \r
345                 return result;\r
346         }\r
347         \r
348         public Collection<Link<T>> getLinks(String rel, GraphNode<T> node) {\r
349                 _checkDisposed();\r
350                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
351 \r
352                 for (Link<T> link : nodes) {\r
353                         if (equals(rel,link.getName()) && link.to().equals(node))\r
354                                 result.add(link);\r
355                 }\r
356                 \r
357                 return result;\r
358         }\r
359         \r
360         public Collection<Link<T>> getLinks(String rel, String inverse) {\r
361                 _checkDisposed();\r
362                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
363 \r
364                 for (Link<T> link : nodes) {\r
365                         if (equals(rel,link.getName()) && equals(inverse, link.getInverseName()))\r
366                                 result.add(link);\r
367                 }\r
368                 \r
369                 return result;\r
370         }\r
371         \r
372         public Collection<Link<T>> getLinks(String rel, String inverse, GraphNode<T> node) {\r
373                 _checkDisposed();\r
374                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
375 \r
376                 for (Link<T> link : nodes) {\r
377                         if (equals(rel,link.getName()) && equals(inverse, link.getInverseName()) && link.to().equals(node))\r
378                                 result.add(link);\r
379                 }\r
380                 \r
381                 return result;\r
382         }\r
383         \r
384         public Collection<GraphNode<T>> getNodesWithInv(String inv) {\r
385                 _checkDisposed();\r
386                 Collection<GraphNode<T>> result = new ArrayList<GraphNode<T>>();\r
387 \r
388                 for (Link<T> link : nodes) {\r
389                         if (equals(inv,link.getInverseName()))\r
390                                 result.add(link.to());\r
391                 }\r
392                 \r
393                 return result;\r
394         }\r
395         \r
396         public Collection<GraphNode<T>> getNodes(String rel, String inv) {\r
397                 _checkDisposed();\r
398                 Collection<GraphNode<T>> result = new ArrayList<GraphNode<T>>();\r
399 \r
400                 for (Link<T> link : nodes) {\r
401                         if (equals(rel,link.getName()) && equals(inv,link.getInverseName()))\r
402                                 result.add(link.to());\r
403                 }\r
404 \r
405                 return result;\r
406         }\r
407         \r
408         public static boolean equals(String s1, String s2) {\r
409                 if (s1 != null)\r
410                         return s1.equals(s2);\r
411                 if (s2 != null)\r
412                         return s2.equals(s1);\r
413                 return true; // both null\r
414         }\r
415         \r
416         \r
417         /**\r
418          * Returns links from this node to the given node.\r
419          * @param node\r
420          * @return\r
421          */\r
422         public Collection<Link<T>> getLinks(GraphNode<T> node) {\r
423                 _checkDisposed();\r
424                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
425                 for (Link<T> link : nodes) {\r
426                         if (link.to().equals(node))\r
427                                 result.add(link);\r
428                 }\r
429                 return result;\r
430         }\r
431         \r
432         /**\r
433          * Returns names of links from this node to the given node. Does not return null names.\r
434          * @param node\r
435          * @return\r
436          */\r
437         public Collection<String> getRelations(GraphNode<T> node) {\r
438                 _checkDisposed();\r
439                 Collection<String> result = new ArrayList<String>();\r
440                 for (Link<T> link : nodes) {\r
441                         if (link.to().equals(node) && link.getName() != null)\r
442                                 result.add(link.getName());\r
443                 }\r
444                 return result;\r
445         }\r
446         \r
447         /**\r
448          * Returns links from given node to this node.\r
449          * @param node\r
450          * @return\r
451          */\r
452         public Collection<Link<T>> getInverseLinks(GraphNode<T> node) {\r
453                 _checkDisposed();\r
454                 Collection<Link<T>> result = new ArrayList<Link<T>>();\r
455                 for (Link<T> link : nodes) {\r
456                         if (link.to().equals(node))\r
457                                 result.add(link.getInverse());\r
458                 }\r
459                 return result;\r
460         }\r
461         \r
462         /**\r
463          * Returns names of links from given node to this node. Does not return null names.\r
464          * @param node\r
465          * @return\r
466          */\r
467         public Collection<String> getInverses(GraphNode<T> node) {\r
468                 _checkDisposed();\r
469                 Collection<String> result = new ArrayList<String>();\r
470                 for (Link<T> link : nodes) {\r
471                         if (link.to().equals(node) && link.getInverseName() != null)\r
472                                 result.add(link.getInverseName());\r
473                 }\r
474                 return result;\r
475         }\r
476         \r
477         \r
478         \r
479         @Override\r
480         public int hashCode() {\r
481                 return data.hashCode();\r
482         }\r
483         \r
484         @Override\r
485         public boolean equals(Object arg0) {\r
486                 if (!arg0.getClass().equals(getClass()))\r
487                         return false;\r
488                 GraphNode<?> other = (GraphNode<?>)arg0;\r
489                 if (this == other)\r
490                         return true;\r
491                 if (this.data == null || other.data == null)\r
492                         return false;\r
493                 if (!data.equals(other.data))\r
494                         return false;\r
495 \r
496                 return true;\r
497         }\r
498         \r
499         /**\r
500          * Merges given nodes to new node. \r
501          * Does not copy hints!\r
502          * @param other\r
503          */\r
504         public GraphNode<T> merge(GraphNode<T> other, T mergedData) {\r
505                 _checkDisposed();\r
506                 GraphNode<T> mergedNode = new GraphNode<T>(mergedData);\r
507                 copyLinks(this, mergedNode);\r
508                 copyLinks(other, mergedNode);\r
509                 \r
510                 //mergedNode.setHints(other.getHints());\r
511                 //mergedNode.setHints(this.getHints());\r
512                 \r
513                 this.destroy();\r
514                 other.destroy();\r
515                 \r
516                 return mergedNode;\r
517         }\r
518         \r
519         \r
520         \r
521         \r
522         \r
523         /**\r
524          * Copies a link to other node.\r
525          * @param from the node containing original link\r
526          * @param to the node where link is copied to\r
527          * @param l the link that is copied.\r
528          * @return created link, if copy is successful. Otherwise returns null.\r
529          */\r
530         public static <T> Link<T> copyLink(GraphNode<T> from, GraphNode<T> to, Link<T> l) {\r
531                 if (l.from() != from)\r
532                         throw new IllegalArgumentException("Link is not starting from " + from + " node.");\r
533                 if (l.to() == to)\r
534                         return null;\r
535                 if (to.containsLink(l.getName(), l.getInverseName(),l.to()))\r
536                         return null;\r
537                 if (l.isMain()) {\r
538                         Link<T> newLink = to.addLink(l.getName(),l.getInverseName(),l.to());\r
539                         if (newLink != null) {\r
540                                 newLink.setHints(l.getHints());\r
541                                 newLink.getInverse().setHints(l.getInverse().getHints());\r
542                                 return newLink;\r
543                         } else {\r
544                                 return null;\r
545                         }\r
546                 } else {\r
547                         Link<T> newLink = l.to().addLink(l.getInverseName(), l.getName(),to);\r
548                         if (newLink != null) {\r
549                                 newLink.setHints(l.getInverse().getHints());\r
550                                 newLink.getInverse().setHints(l.getHints());\r
551                                 return newLink.getInverse();\r
552                         } else {\r
553                                 return null;\r
554                         }\r
555                 }       \r
556                 \r
557         }\r
558         \r
559         /**\r
560          * Copies a link to other node, but inverts its direction.\r
561          * @param from the node containing original link\r
562          * @param to the node where link is copied to\r
563          * @param l the link that is copied.\r
564          * @return created link, if copy is successful. Otherwise returns null.\r
565          */\r
566         public static <T> Link<T> copyLinkInverse(GraphNode<T> from, GraphNode<T> to, Link<T> l) {\r
567                 if (l.from() != from)\r
568                         throw new IllegalArgumentException("Link is not starting from " + from + " node.");\r
569                 if (l.to() == to)\r
570                         return null;\r
571                 if (to.containsLink(l.getInverseName(), l.getName(),l.to()))\r
572                         return null;\r
573                 if (l.isMain()) {\r
574                         Link<T> newLink = l.to().addLink(l.getName(),l.getInverseName(),to);\r
575                         if (newLink != null) {\r
576                                 newLink.setHints(l.getHints());\r
577                                 newLink.getInverse().setHints(l.getInverse().getHints());\r
578                                 return newLink;\r
579                         } else {\r
580                                 return null;\r
581                         }\r
582                 } else {\r
583                         Link<T> newLink = to.addLink(l.getInverseName(), l.getName(),l.to());\r
584                         if (newLink != null) {\r
585                                 newLink.setHints(l.getInverse().getHints());\r
586                                 newLink.getInverse().setHints(l.getHints());\r
587                                 return newLink.getInverse();\r
588                         } else {\r
589                                 return null;\r
590                         }\r
591                 }       \r
592                 \r
593         }\r
594 \r
595         public static <T> void copyLinks(GraphNode<T> from, GraphNode<T> to, Collection<Link<T>> links) {\r
596                 for (Link<T> l : links) {\r
597                         copyLink(from, to, l);\r
598                 }\r
599         }\r
600 \r
601         \r
602         public static <T> void copyLinks(GraphNode<T> from, GraphNode<T> to) {\r
603                 for (Link<T> l : from.getLinks()) {\r
604                         copyLink(from, to, l);\r
605                 }\r
606         }\r
607         \r
608         /**\r
609          * Copies a link to other node and removes the original link. If move is not successful, the original link is not removed.\r
610          * @param from the node containing original link\r
611          * @param to the node where link is copied to\r
612          * @param l the link that is moved.\r
613          * @return created link, if move is successful. Otherwise returns null. \r
614          */\r
615         public static <T> Link<T> moveLink(GraphNode<T> from, GraphNode<T> to, Link<T> l) {\r
616                 Link<T> newLink = copyLink(from, to, l);\r
617                 if (newLink != null) {\r
618                         from.removeLink(l);\r
619                         return newLink;\r
620                 }\r
621                 return null;\r
622         }\r
623         \r
624         public static <T> void moveLinks(GraphNode<T> from, GraphNode<T> to, Collection<Link<T>> links) {\r
625                 for (Link<T> l : links) {\r
626                         Link<T> newLink = copyLink(from, to, l);\r
627                         if (newLink != null) {\r
628                                 from.removeLink(l);\r
629                         }       \r
630                 }\r
631         }\r
632         \r
633         public static <T> void moveLinkInverses(GraphNode<T> from, GraphNode<T> to, Collection<Link<T>> links) {\r
634                 for (Link<T> l : links) {\r
635                         Link<T> newLink = copyLinkInverse(from, to, l);\r
636                         if (newLink != null) {\r
637                                 from.removeLink(l);\r
638                         }       \r
639                 }\r
640         }\r
641         \r
642         public static <T> void moveLinks(GraphNode<T> from, GraphNode<T> to) {\r
643                 for (Link<T> l : from.getLinks()) {\r
644                         Link<T> newLink = copyLink(from, to, l);\r
645                         if (newLink != null) {\r
646                                 from.removeLink(l);\r
647                         }       \r
648                 }\r
649         }\r
650         \r
651         /**\r
652          * Replaces a link with a link going first to given node, and the to the original destination.\r
653          * The link names and hints are copied to the created links.\r
654          * \r
655          * Example: link is 'a' -> 'b'. With insert attribute 'c', the result is 'a' -> 'c' -> 'b'.\r
656          *   \r
657          * @param link\r
658          * @param insert\r
659          * @return Array containing created links (2).\r
660          */\r
661         @SuppressWarnings("unchecked")\r
662         public static <T> Link<T>[] insert(Link<T> link, GraphNode<T> insert) {\r
663                 GraphNode<T> a = link.from();\r
664                 Link<T> c_b = moveLink(a, insert, link);\r
665                 Link<T> a_c = a.addLink(c_b, insert);\r
666                 return new Link[]{a_c,c_b};\r
667         }\r
668 \r
669         \r
670         \r
671         /**\r
672          * Finds all nodes that have the same relations to the same nodes as this node. \r
673          * @return\r
674          */\r
675         public Collection<GraphNode<T>> getFullSimilars() {\r
676                 _checkDisposed();\r
677                 Collection<GraphNode<T>> result = new ArrayList<GraphNode<T>>();\r
678                 Set<GraphNode<T>> potential = new HashSet<GraphNode<T>>();\r
679                 for (Link<T> link : nodes) {\r
680                         for (Link<T> link2 : link.to().nodes) {\r
681                                 if (!link2.to().equals(this))\r
682                                         potential.add(link2.to());\r
683                         }\r
684                 }\r
685                 for (GraphNode<T> node : potential) {\r
686                         if (node.nodes.containsAll(nodes))\r
687                                 result.add(node);\r
688                 }\r
689                 \r
690                 return result;\r
691         }\r
692         \r
693         /**\r
694          * Finds all nodes that have at least one similar relation to the same nodes as this node. \r
695          * @return\r
696          */\r
697         public Collection<GraphNode<T>> getSemiSimilars() {\r
698                 _checkDisposed();\r
699                 Collection<GraphNode<T>> result = new ArrayList<GraphNode<T>>();\r
700                 Set<GraphNode<T>> potential = new HashSet<GraphNode<T>>();\r
701                 for (Link<T> link : nodes) {\r
702                         for (Link<T> link2 : link.to().nodes) {\r
703                                 if (!link2.to().equals(this))\r
704                                         potential.add(link2.to());\r
705                         }\r
706                 }\r
707                 for (GraphNode<T> node : potential) {\r
708                         for (Link<T> link : nodes) {\r
709                                 if (node.nodes.contains(link))\r
710                                         result.add(node);\r
711                         }\r
712                 }\r
713                 \r
714                 return result;\r
715         }\r
716         \r
717 \r
718         /**\r
719          * Disposes this node. Removes all the links that connect to this node.\r
720          */\r
721         public void destroy() {\r
722                 if (disposed)\r
723                         return;\r
724                 LOGGER.info("Node destroy " + data + " " + this);\r
725                 Collection<Link<T>> coll = new ArrayList<Link<T>>();\r
726                 coll.addAll(nodes);\r
727                 nodes.clear();\r
728                 for (Link<T> link : coll) {\r
729                         link.to()._removeLink(this);\r
730                 }\r
731                 nodes = null;\r
732                 disposed = true;\r
733         }\r
734         \r
735         /**\r
736          * Removes this node from the graph, and reconnects parents and children of this node.\r
737          */\r
738         public void remove() {\r
739                 if (disposed)\r
740                         return;\r
741                 // FIXME: link.to may be *this.\r
742                 LOGGER.info("Node remove " + data + " " + this);\r
743                 if (nodes.size() == 1) {\r
744                         Link<T> link = nodes.get(0);\r
745                         link.to().removeLink(link.getInverseName(), link.getName(), this);\r
746                 } else {\r
747                         for (int i = 0; i < nodes.size() -1 ; i++) {\r
748                                 Link<T> link1 = nodes.get(i);\r
749                                 link1.to()._removeLink(link1.getInverseName(), link1.getName(), this);\r
750                                 for (int j = i+1; j < nodes.size(); j++) {\r
751                                         Link<T> link2 = nodes.get(j);\r
752                                         link2.to()._removeLink(link2.getInverseName(), link2.getName(), this);\r
753                                         if (link1.to().equals(link2.to()))\r
754                                                 continue;\r
755                                         link1.to().addLink(link1.getInverseName(),link2.getInverseName(),link2.to());\r
756                                 }\r
757                                 \r
758                         }\r
759                 }\r
760                 \r
761                 nodes.clear();\r
762                 nodes = null;\r
763                 disposed = true;\r
764 \r
765         }\r
766         \r
767         /**\r
768          * \r
769          * @return true if the node has been disposed and cannot be used anymore.\r
770          */\r
771         public boolean isDisposed() {\r
772                 return disposed;\r
773         }\r
774         \r
775         /**\r
776          * Dispose the node and all nodes that are in the same graph.\r
777          */\r
778         public void dispose() {\r
779                 if (disposed)\r
780                         return;\r
781                 Collection<Link<T>> links = new ArrayList<Link<T>>();\r
782                 links.addAll(nodes);\r
783                 nodes.clear();\r
784                 for (Link<T> l : links)\r
785                         l.to().dispose();\r
786                 links.clear();\r
787                 nodes = null;\r
788                 disposed = true;\r
789         }\r
790         \r
791 \r
792         protected void _checkDisposed() {\r
793                 if (disposed) {\r
794                         LOGGER.error("Remove Node, disposed " + this);\r
795                         throw new RuntimeException("Node " + this + " is disposed.");\r
796                 }\r
797         }\r
798         \r
799         \r
800         public int distanceTo(GraphNode<T> node, String rel, String inv) {\r
801                 if (node.equals(this))\r
802                         return 0;\r
803                 int count = 0;\r
804                 Set<GraphNode<T>> processed = new HashSet<GraphNode<T>>();\r
805                 Set<GraphNode<T>> next = new HashSet<GraphNode<T>>();\r
806                 next.add(this);\r
807                 while (true) {\r
808                         if (next.size() == 0)\r
809                                 return -1;\r
810                         count++;\r
811                         processed.addAll(next);\r
812                         Set<GraphNode<T>> nextNext = new HashSet<GraphNode<T>>();\r
813                         for (GraphNode<T> n : next) {\r
814                                 for (GraphNode<T> nn : n.getNodes(rel, inv))\r
815                                         if (!processed.contains(nn))\r
816                                                 nextNext.add(nn);\r
817                         }\r
818                         next = nextNext;\r
819                         if (next.contains(node))\r
820                                 return count;\r
821                 }\r
822         }\r
823         \r
824         public String toString() {\r
825                 return "Node : " + data;\r
826         }\r
827 }\r