1 package org.simantics.db.common.utils.traverser;
\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
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
24 * Traverse query is generic query that traverses accroding to given rules.
\r
25 * Use {@link TraverseQueryBuilder} to construct traverse query
\r
27 * @author toni.kalajainen@semantum.fi
\r
29 public class TraverseQuery implements Read<TraverseResult>, ReadInterface<TraverseResult> {
\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
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
55 this.startResources = startResources;
\r
56 this.relations = relations;
\r
57 this.instancesOfTypesToFollowTo = instancesOfTypesToFollowTo;
\r
58 this.instancesOfTypesToAddToResult = instancesOfTypesToAddToResult;
\r
60 this.inheritedFromTypesToFollowTo = inheritedFromTypesToFollowTo;
\r
61 this.inheritedFromTypesToAddToResult = inheritedFromTypesToAddToResult;
\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
73 public int hashCode() {
\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
83 if (hash != other.hash) return false;
\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
97 public void request(AsyncRequestProcessor processor, AsyncProcedure<TraverseResult> procedure) {
\r
98 processor.asyncRequest(this, procedure);
\r
102 public void request(AsyncRequestProcessor processor, Procedure<TraverseResult> procedure) {
\r
103 processor.asyncRequest(this, procedure);
\r
107 public void request(AsyncRequestProcessor processor, SyncProcedure<TraverseResult> procedure) {
\r
108 processor.asyncRequest(this, procedure);
\r
112 public void request(AsyncRequestProcessor processor, AsyncListener<TraverseResult> procedure) {
\r
113 processor.asyncRequest(this, procedure);
\r
117 public void request(AsyncRequestProcessor processor, Listener<TraverseResult> procedure) {
\r
118 processor.asyncRequest(this, procedure);
\r
122 public void request(AsyncRequestProcessor processor, SyncListener<TraverseResult> procedure) {
\r
123 processor.asyncRequest(this, procedure);
\r
127 public TraverseResult request(RequestProcessor processor) throws DatabaseException {
\r
128 return processor.syncRequest(this);
\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
136 while ( !traverser.toBeVisited.isEmpty() ) {
\r
137 _doTraverse(graph, traverser);
\r
140 return traverser.result;
\r
143 void _doTraverse(ReadGraph graph, Traverser traverser) throws ServiceException {
\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
151 for (Resource relation : relations) {
\r
153 for (Resource obj : graph.getObjects(r, relation)) {
\r
154 if (traverser.visited.contains(obj)) continue nextObj;
\r
156 boolean isAcceptedObject = false;
\r
157 for (Resource acceptedType : instancesOfTypesToFollowTo) {
\r
158 isAcceptedObject |= graph.isInstanceOf(obj, acceptedType);
\r
159 if ( isAcceptedObject ) break;
\r
161 if ( !isAcceptedObject ) {
\r
162 for (Resource acceptedType : inheritedFromTypesToFollowTo) {
\r
163 isAcceptedObject |= graph.isInheritedFrom(obj, acceptedType);
\r
164 if ( isAcceptedObject ) break;
\r
167 if ( !isAcceptedObject ) continue nextObj;
\r
169 traverser.toBeVisited.add(obj);
\r
174 boolean addToResult = false;
\r
175 for (Resource typeToAddToResult : instancesOfTypesToAddToResult) {
\r
176 addToResult |= graph.isInstanceOf(r, typeToAddToResult);
\r
177 if ( addToResult) break;
\r
180 for (Resource typeToAddToResult : inheritedFromTypesToAddToResult) {
\r
181 addToResult |= graph.isInheritedFrom(r, typeToAddToResult);
\r
182 if ( addToResult) break;
\r
185 if ( addToResult ) {
\r
186 traverser.result.result.add(r);
\r
189 traverser.visited.add(r);
\r
195 TraverseResult result = new TraverseResult();
\r
197 public Set<Resource> visited = new HashSet<Resource>();
\r
198 public LinkedList<Resource> toBeVisited = new LinkedList<Resource>();
\r