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