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