]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.common/src/org/simantics/db/common/utils/traverser/TraverseQuery.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.common / src / org / simantics / db / common / utils / traverser / TraverseQuery.java
1 package org.simantics.db.common.utils.traverser;\r
2 \r
3 import java.util.Arrays;\r
4 import java.util.HashSet;\r
5 import java.util.LinkedList;\r
6 import java.util.Set;\r
7 \r
8 import org.simantics.db.AsyncRequestProcessor;\r
9 import org.simantics.db.ReadGraph;\r
10 import org.simantics.db.RequestProcessor;\r
11 import org.simantics.db.Resource;\r
12 import org.simantics.db.exception.DatabaseException;\r
13 import org.simantics.db.exception.ServiceException;\r
14 import org.simantics.db.procedure.AsyncListener;\r
15 import org.simantics.db.procedure.AsyncProcedure;\r
16 import org.simantics.db.procedure.Listener;\r
17 import org.simantics.db.procedure.Procedure;\r
18 import org.simantics.db.procedure.SyncListener;\r
19 import org.simantics.db.procedure.SyncProcedure;\r
20 import org.simantics.db.request.Read;\r
21 import org.simantics.db.request.ReadInterface;\r
22 \r
23 /**\r
24  * Traverse query is generic query that traverses accroding to given rules.\r
25  * Use {@link TraverseQueryBuilder} to construct traverse query\r
26  *\r
27  * @author toni.kalajainen@semantum.fi\r
28  */\r
29 public class TraverseQuery implements Read<TraverseResult>, ReadInterface<TraverseResult> {\r
30 \r
31         // Start locations\r
32     public final Resource[] startResources;\r
33     // Instances of types to follow to\r
34     public final Resource[] instancesOfTypesToFollowTo;\r
35     // Instances of types to follow to\r
36     public final Resource[] inheritedFromTypesToFollowTo;\r
37     // Relations to traverse \r
38     public final Resource[] relations;\r
39     // Types to add to result\r
40     public final Resource[] instancesOfTypesToAddToResult;\r
41     // Types to add to result\r
42     public final Resource[] inheritedFromTypesToAddToResult;\r
43 \r
44     private int hash;\r
45     \r
46     public TraverseQuery(\r
47                 Resource[] startResources, \r
48                 Resource[] instancesOfTypesToFollowTo, \r
49                 Resource[] relations, \r
50                 Resource[] instancesOfTypesToAddToResult,\r
51                 Resource[] inheritedFromTypesToFollowTo,\r
52                 Resource[] inheritedFromTypesToAddToResult\r
53                 )\r
54     {\r
55         this.startResources = startResources;\r
56         this.relations = relations;\r
57         this.instancesOfTypesToFollowTo = instancesOfTypesToFollowTo;\r
58         this.instancesOfTypesToAddToResult = instancesOfTypesToAddToResult;\r
59 \r
60         this.inheritedFromTypesToFollowTo = inheritedFromTypesToFollowTo;\r
61         this.inheritedFromTypesToAddToResult = inheritedFromTypesToAddToResult;\r
62         \r
63         int hash = 345436534;\r
64         for (Resource r : startResources) hash = 13*hash + r.hashCode();\r
65         for (Resource r : relations) hash = 7*hash + r.hashCode();\r
66         for (Resource r : instancesOfTypesToFollowTo) hash = 3*hash + r.hashCode();\r
67         for (Resource r : instancesOfTypesToAddToResult) hash = 11*hash + r.hashCode();\r
68         for (Resource r : inheritedFromTypesToFollowTo) hash = 3*hash + r.hashCode();\r
69         for (Resource r : inheritedFromTypesToAddToResult) hash = 11*hash + r.hashCode();\r
70     }\r
71         \r
72     @Override\r
73     public int hashCode() {\r
74         return hash;\r
75     }\r
76 \r
77     @Override\r
78     public boolean equals(Object object) {\r
79         if (this == object) return true;\r
80         if ( object instanceof TraverseQuery == false ) return false;\r
81         TraverseQuery other = (TraverseQuery) this;\r
82         \r
83         if (hash != other.hash) return false;\r
84         \r
85         // The order should not count - but who cares\r
86         if (!Arrays.deepEquals(startResources, other.startResources)) return false;\r
87         if (!Arrays.deepEquals(relations, other.relations)) return false;\r
88         if (!Arrays.deepEquals(instancesOfTypesToFollowTo, other.instancesOfTypesToFollowTo)) return false;\r
89         if (!Arrays.deepEquals(instancesOfTypesToAddToResult, other.instancesOfTypesToAddToResult)) return false;\r
90         if (!Arrays.deepEquals(inheritedFromTypesToFollowTo, other.inheritedFromTypesToFollowTo)) return false;\r
91         if (!Arrays.deepEquals(inheritedFromTypesToAddToResult, other.inheritedFromTypesToAddToResult)) return false;\r
92 \r
93         return true;\r
94     }\r
95 \r
96     @Override\r
97     public void request(AsyncRequestProcessor processor, AsyncProcedure<TraverseResult> procedure) {\r
98         processor.asyncRequest(this, procedure);\r
99     }\r
100     \r
101     @Override\r
102     public void request(AsyncRequestProcessor processor, Procedure<TraverseResult> procedure) {\r
103         processor.asyncRequest(this, procedure);\r
104     }\r
105     \r
106     @Override\r
107     public void request(AsyncRequestProcessor processor, SyncProcedure<TraverseResult> procedure) {\r
108         processor.asyncRequest(this, procedure);\r
109     }\r
110 \r
111     @Override\r
112     public void request(AsyncRequestProcessor processor, AsyncListener<TraverseResult> procedure) {\r
113         processor.asyncRequest(this, procedure);\r
114     }\r
115     \r
116     @Override\r
117     public void request(AsyncRequestProcessor processor, Listener<TraverseResult> procedure) {\r
118         processor.asyncRequest(this, procedure);\r
119     }\r
120     \r
121     @Override\r
122     public void request(AsyncRequestProcessor processor, SyncListener<TraverseResult> procedure) {\r
123         processor.asyncRequest(this, procedure);\r
124     }\r
125     \r
126     @Override\r
127     public TraverseResult request(RequestProcessor processor) throws DatabaseException {\r
128         return processor.syncRequest(this);\r
129     }\r
130 \r
131         @Override\r
132         public TraverseResult perform(ReadGraph graph) throws DatabaseException {\r
133                 Traverser traverser = new Traverser();\r
134                 for (Resource r : startResources) traverser.toBeVisited.add(r);\r
135                 \r
136                 while ( !traverser.toBeVisited.isEmpty() ) {\r
137                         _doTraverse(graph, traverser);\r
138                 }\r
139                 \r
140                 return traverser.result;\r
141         }\r
142         \r
143         void _doTraverse(ReadGraph graph, Traverser traverser) throws ServiceException {\r
144                 \r
145                 // Remove one resource\r
146                 while (!traverser.toBeVisited.isEmpty()) {\r
147                         Resource r = traverser.toBeVisited.removeFirst();\r
148                         if ( traverser.visited.contains(r) ) continue;\r
149                         \r
150                         // Get Objects\r
151                         for (Resource relation : relations)     {\r
152                                 nextObj:\r
153                                 for (Resource obj : graph.getObjects(r, relation)) {\r
154                                         if (traverser.visited.contains(obj)) continue nextObj;\r
155                                         \r
156                                         boolean isAcceptedObject = false;\r
157                                         for (Resource acceptedType : instancesOfTypesToFollowTo) {\r
158                                                 isAcceptedObject |= graph.isInstanceOf(obj, acceptedType);\r
159                                                 if ( isAcceptedObject ) break;\r
160                                         }\r
161                                         if ( !isAcceptedObject ) {\r
162                                                 for (Resource acceptedType : inheritedFromTypesToFollowTo) {\r
163                                                         isAcceptedObject |= graph.isInheritedFrom(obj, acceptedType);\r
164                                                         if ( isAcceptedObject ) break;\r
165                                                 }\r
166                                         }\r
167                                         if ( !isAcceptedObject ) continue nextObj;\r
168                                         \r
169                                         traverser.toBeVisited.add(obj);\r
170                                 }\r
171                         }\r
172                         \r
173                         // Add to result?\r
174                         boolean addToResult = false;\r
175                         for (Resource typeToAddToResult : instancesOfTypesToAddToResult) {\r
176                                 addToResult |= graph.isInstanceOf(r, typeToAddToResult);\r
177                                 if ( addToResult) break;\r
178                         }\r
179                         if (!addToResult)\r
180                         for (Resource typeToAddToResult : inheritedFromTypesToAddToResult) {\r
181                                 addToResult |= graph.isInheritedFrom(r, typeToAddToResult);\r
182                                 if ( addToResult) break;\r
183                         }\r
184 \r
185                         if ( addToResult ) {\r
186                                 traverser.result.result.add(r);\r
187                         }\r
188                         \r
189                         traverser.visited.add(r);\r
190                 }\r
191         }\r
192 \r
193         class Traverser {\r
194                 \r
195                 TraverseResult result = new TraverseResult();   \r
196 \r
197                 public Set<Resource> visited = new HashSet<Resource>();\r
198                 public LinkedList<Resource> toBeVisited = new LinkedList<Resource>();\r
199                 \r
200         }\r
201         \r
202         \r
203 }