1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.db.layer0.request.combinations;
\r
14 import java.util.HashMap;
\r
15 import java.util.Map;
\r
17 import org.simantics.db.ReadGraph;
\r
18 import org.simantics.db.Resource;
\r
19 import org.simantics.db.common.request.ParametrizedRead;
\r
20 import org.simantics.db.exception.DatabaseException;
\r
21 import org.simantics.db.procedure.AsyncMultiProcedure;
\r
22 import org.simantics.db.procedure.Procedure;
\r
23 import org.simantics.db.request.MultiRead;
\r
24 import org.simantics.db.request.Read;
\r
25 import org.simantics.layer0.Layer0;
\r
28 * Functions that create new read requests by combining simpler ones.
\r
29 * @author Hannu Niemist�
\r
31 public class Combinators {
\r
33 // ------------------------------------------------------------------------
\r
35 private static class Objects implements MultiRead<Resource> {
\r
38 public Objects(Resource subject, Resource relation) {
\r
39 this.subject = subject;
\r
40 this.relation = relation;
\r
43 public void perform(ReadGraph graph,
\r
44 AsyncMultiProcedure<Resource> callback)
\r
45 throws DatabaseException {
\r
46 graph.forEachObject(subject, relation, callback);
\r
49 public int hashCode() {
\r
50 return subject.hashCode() + 31 * relation.hashCode();
\r
53 public boolean equals(Object object) {
\r
54 if (this == object) return true;
\r
55 else if (object == null || getClass() != object.getClass()) return false;
\r
56 Objects other = (Objects)object;
\r
57 return subject.equals(other.subject) && relation.equals(other.relation);
\r
62 * Returns a multi read request that reads the objects of given subject and relation.
\r
64 public static MultiRead<Resource> objects(Resource subject, Resource relation) {
\r
65 return new Objects(subject, relation);
\r
68 // ------------------------------------------------------------------------
\r
70 private static class Relation implements ParametrizedMultiRead<Resource, Resource> {
\r
72 public Relation(Resource relation) {
\r
73 this.relation = relation;
\r
76 public MultiRead<Resource> get(Resource subject) {
\r
77 return objects(subject, relation);
\r
80 public int hashCode() {
\r
81 return getClass().hashCode() + 31 * relation.hashCode();
\r
84 public boolean equals(Object obj) {
\r
85 if(obj == this) return true;
\r
86 if(obj == null || obj.getClass() != getClass()) return false;
\r
87 Relation other = (Relation)obj;
\r
88 return relation.equals(other.relation);
\r
93 * Returns a function <code>subject -> objects(subject, relation)</code>.
\r
95 public static ParametrizedMultiRead<Resource,Resource> relation(Resource relation) {
\r
96 return new Relation(relation);
\r
99 // ------------------------------------------------------------------------
\r
101 public static class SynchronizationProcedure<T> implements Procedure<T> {
\r
103 DatabaseException exception;
\r
104 boolean ready = false;
\r
106 public synchronized void exception(Throwable t) {
\r
108 t instanceof DatabaseException ? (DatabaseException)t : new DatabaseException(t);
\r
113 public synchronized void execute(T result) {
\r
114 this.result = result;
\r
118 public synchronized T getResult() throws DatabaseException {
\r
122 } catch (InterruptedException e) {
\r
123 throw new DatabaseException(e);
\r
126 if(exception != null)
\r
132 private static class PossibleObject implements Read<Resource> {
\r
135 public PossibleObject(Resource subject, Resource relation) {
\r
136 this.subject = subject;
\r
137 this.relation = relation;
\r
140 public Resource perform(ReadGraph graph) throws DatabaseException {
\r
141 SynchronizationProcedure<Resource> procedure = new SynchronizationProcedure<Resource>();
\r
142 graph.forPossibleObject(subject, relation, procedure);
\r
143 return procedure.getResult();
\r
146 public int hashCode() {
\r
147 return subject.hashCode() + 31 * relation.hashCode();
\r
150 public boolean equals(Object object) {
\r
151 if (this == object) return true;
\r
152 else if (object == null || getClass() != object.getClass()) return false;
\r
153 PossibleObject other = (PossibleObject)object;
\r
154 return subject.equals(other.subject) && relation.equals(other.relation);
\r
159 * Returns a read request that reads an object possibly connected to the subject by the relation.
\r
161 public static Read<Resource> possibleObject(Resource subject, Resource relation) {
\r
162 return new PossibleObject(subject, relation);
\r
165 // ------------------------------------------------------------------------
\r
167 private static class PartialFunction implements ParametrizedRead<Resource, Resource> {
\r
169 public PartialFunction(Resource relation) {
\r
170 this.relation = relation;
\r
173 public Read<Resource> get(Resource subject) {
\r
174 return possibleObject(subject, relation);
\r
177 public int hashCode() {
\r
178 return getClass().hashCode() + 31 * relation.hashCode();
\r
181 public boolean equals(Object obj) {
\r
182 if(obj == this) return true;
\r
183 if(obj == null || obj.getClass() != getClass()) return false;
\r
184 PartialFunction other = (PartialFunction)obj;
\r
185 return relation.equals(other.relation);
\r
190 * Returns a function <code>subject -> possibleObject(subject, relation)</code>.
\r
192 public static ParametrizedRead<Resource,Resource> partialFunction(Resource relation) {
\r
193 return new PartialFunction(relation);
\r
196 // ------------------------------------------------------------------------
\r
198 private static class SingleObject implements Read<Resource> {
\r
201 public SingleObject(Resource subject, Resource relation) {
\r
202 this.subject = subject;
\r
203 this.relation = relation;
\r
206 public Resource perform(ReadGraph graph) throws DatabaseException {
\r
207 SynchronizationProcedure<Resource> procedure = new SynchronizationProcedure<Resource>();
\r
208 graph.forSingleObject(subject, relation, procedure);
\r
209 return procedure.getResult();
\r
212 public int hashCode() {
\r
213 return subject.hashCode() + 31 * relation.hashCode();
\r
216 public boolean equals(Object object) {
\r
217 if (this == object) return true;
\r
218 else if (object == null || getClass() != object.getClass()) return false;
\r
219 SingleObject other = (SingleObject)object;
\r
220 return subject.equals(other.subject) && relation.equals(other.relation);
\r
225 * Returns a read request that reads an object connected to the subject by the relation.
\r
227 public static Read<Resource> singleObject(Resource subject, Resource relation) {
\r
228 return new SingleObject(subject, relation);
\r
231 // ------------------------------------------------------------------------
\r
233 private static class CompleteFunction implements ParametrizedRead<Resource, Resource> {
\r
235 public CompleteFunction(Resource relation) {
\r
236 this.relation = relation;
\r
239 public Read<Resource> get(Resource subject) {
\r
240 return singleObject(subject, relation);
\r
243 public int hashCode() {
\r
244 return getClass().hashCode() + 31 * relation.hashCode();
\r
247 public boolean equals(Object obj) {
\r
248 if(obj == this) return true;
\r
249 if(obj == null || obj.getClass() != getClass()) return false;
\r
250 CompleteFunction other = (CompleteFunction)obj;
\r
251 return relation.equals(other.relation);
\r
256 * Returns a function <code>subject -> singleObject(subject, relation)</code>.
\r
258 public static ParametrizedRead<Resource,Resource> completeFunction(Resource relation) {
\r
259 return new CompleteFunction(relation);
\r
262 // ------------------------------------------------------------------------
\r
264 private static class Compose1<X, Y> implements Read<Y> {
\r
265 final ParametrizedRead<X, Y> f;
\r
267 public Compose1(ParametrizedRead<X, Y> f, Read<X> g) {
\r
272 public Y perform(ReadGraph graph) throws DatabaseException {
\r
273 return graph.syncRequest(f.get(graph.syncRequest(g)));
\r
276 public int hashCode() {
\r
277 return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
\r
280 public boolean equals(Object obj) {
\r
281 if(obj == this) return true;
\r
282 if(obj == null || obj.getClass() != getClass()) return false;
\r
283 Compose1<?, ?> other = (Compose1<?, ?>)obj;
\r
284 return f.equals(other.f) && g.equals(other.g);
\r
288 public static <X, Y> Read<Y> compose(ParametrizedRead<X, Y> f, Read<X> g) {
\r
289 return new Compose1<X, Y>(f, g);
\r
292 // ------------------------------------------------------------------------
\r
294 private static class Compose2<X, Y, Z> implements ParametrizedRead<X, Z> {
\r
295 final ParametrizedRead<Y, Z> f;
\r
296 final ParametrizedRead<X, Y> g;
\r
297 public Compose2(ParametrizedRead<Y, Z> f, ParametrizedRead<X, Y> g) {
\r
301 public Read<Z> get(X x) {
\r
302 return compose(f, g.get(x));
\r
305 public int hashCode() {
\r
306 return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
\r
309 public boolean equals(Object obj) {
\r
310 if(obj == this) return true;
\r
311 if(obj == null || obj.getClass() != getClass()) return false;
\r
312 Compose2<?, ?, ?> other = (Compose2<?, ?, ?>)obj;
\r
313 return f.equals(other.f) && g.equals(other.g);
\r
317 public static <X, Y, Z> ParametrizedRead<X, Z> compose(ParametrizedRead<Y, Z> f, ParametrizedRead<X, Y> g) {
\r
318 return new Compose2<X, Y, Z>(f, g);
\r
321 // ------------------------------------------------------------------------
\r
323 private static class Compose3<X, Y> implements MultiRead<Y> {
\r
324 final ParametrizedRead<X, Y> f;
\r
325 final MultiRead<X> g;
\r
326 public Compose3(ParametrizedRead<X, Y> f, MultiRead<X> g) {
\r
330 public void perform(ReadGraph graph, final AsyncMultiProcedure<Y> callback) throws DatabaseException {
\r
332 for(X x : graph.syncRequest(g))
\r
333 callback.execute(graph, graph.syncRequest(f.get(x)));
\r
334 callback.finished(graph);
\r
335 } catch(DatabaseException e) {
\r
336 callback.exception(graph, e);
\r
338 /*// Not sure if this is correct
\r
339 graph.syncRequest(g, new SyncMultiProcedure<X>() {
\r
341 public void exception(ReadGraph graph, Throwable throwable)
\r
342 throws DatabaseException {
\r
343 callback.exception(graph, throwable);
\r
346 public void execute(ReadGraph graph, X x)
\r
347 throws DatabaseException {
\r
348 callback.execute(graph, graph.syncRequest(f.get(x)));
\r
351 public void finished(ReadGraph graph)
\r
352 throws DatabaseException {
\r
355 callback.finished(graph);*/
\r
358 public int hashCode() {
\r
359 return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
\r
362 public boolean equals(Object obj) {
\r
363 if(obj == this) return true;
\r
364 if(obj == null || obj.getClass() != getClass()) return false;
\r
365 Compose3<?, ?> other = (Compose3<?, ?>)obj;
\r
366 return f.equals(other.f) && g.equals(other.g);
\r
370 public static <X, Y> MultiRead<Y> compose(ParametrizedRead<X, Y> f, MultiRead<X> g) {
\r
371 return new Compose3<X, Y>(f, g);
\r
374 // ------------------------------------------------------------------------
\r
376 private static class Compose4<X, Y, Z> implements ParametrizedMultiRead<X, Z> {
\r
377 final ParametrizedRead<Y, Z> f;
\r
378 final ParametrizedMultiRead<X, Y> g;
\r
379 public Compose4(ParametrizedRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
\r
383 public MultiRead<Z> get(X x) {
\r
384 return compose(f, g.get(x));
\r
387 public int hashCode() {
\r
388 return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
\r
391 public boolean equals(Object obj) {
\r
392 if(obj == this) return true;
\r
393 if(obj == null || obj.getClass() != getClass()) return false;
\r
394 Compose4<?, ?, ?> other = (Compose4<?, ?, ?>)obj;
\r
395 return f.equals(other.f) && g.equals(other.g);
\r
399 public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
\r
400 return new Compose4<X, Y, Z>(f, g);
\r
403 // ------------------------------------------------------------------------
\r
405 private static class Compose5<X, Y> implements MultiRead<Y> {
\r
406 final ParametrizedMultiRead<X, Y> f;
\r
408 public Compose5(ParametrizedMultiRead<X, Y> f, Read<X> g) {
\r
413 public void perform(ReadGraph graph, AsyncMultiProcedure<Y> callback)
\r
414 throws DatabaseException {
\r
415 graph.syncRequest(f.get(graph.syncRequest(g)), callback);
\r
418 public int hashCode() {
\r
419 return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
\r
422 public boolean equals(Object obj) {
\r
423 if(obj == this) return true;
\r
424 if(obj == null || obj.getClass() != getClass()) return false;
\r
425 Compose5<?, ?> other = (Compose5<?, ?>)obj;
\r
426 return f.equals(other.f) && g.equals(other.g);
\r
430 public static <X, Y> MultiRead<Y> compose(ParametrizedMultiRead<X, Y> f, Read<X> g) {
\r
431 return new Compose5<X, Y>(f, g);
\r
434 // ------------------------------------------------------------------------
\r
436 private static class Compose6<X, Y, Z> implements ParametrizedMultiRead<X, Z> {
\r
437 final ParametrizedMultiRead<Y, Z> f;
\r
438 final ParametrizedRead<X, Y> g;
\r
439 public Compose6(ParametrizedMultiRead<Y, Z> f, ParametrizedRead<X, Y> g) {
\r
443 public MultiRead<Z> get(X x) {
\r
444 return compose(f, g.get(x));
\r
447 public int hashCode() {
\r
448 return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
\r
451 public boolean equals(Object obj) {
\r
452 if(obj == this) return true;
\r
453 if(obj == null || obj.getClass() != getClass()) return false;
\r
454 Compose6<?, ?, ?> other = (Compose6<?, ?, ?>)obj;
\r
455 return f.equals(other.f) && g.equals(other.g);
\r
459 public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedMultiRead<Y, Z> f, ParametrizedRead<X, Y> g) {
\r
460 return new Compose6<X, Y, Z>(f, g);
\r
463 // ------------------------------------------------------------------------
\r
465 private static class Compose7<X, Y> implements MultiRead<Y> {
\r
466 final ParametrizedMultiRead<X, Y> f;
\r
467 final MultiRead<X> g;
\r
468 public Compose7(ParametrizedMultiRead<X, Y> f, MultiRead<X> g) {
\r
472 public void perform(ReadGraph graph, final AsyncMultiProcedure<Y> callback) throws DatabaseException {
\r
474 for(X x : graph.syncRequest(g))
\r
475 for(Y y : graph.syncRequest(f.get(x)))
\r
476 callback.execute(graph, y);
\r
477 callback.finished(graph);
\r
478 } catch(DatabaseException e) {
\r
479 callback.exception(graph, e);
\r
481 /*// Not correct because inner syncRequest calls callback.finished
\r
482 graph.syncRequest(g, new SyncMultiProcedure<X>() {
\r
484 public void exception(ReadGraph graph, Throwable throwable)
\r
485 throws DatabaseException {
\r
486 callback.exception(graph, throwable);
\r
489 public void execute(ReadGraph graph, X x) throws DatabaseException {
\r
490 graph.syncRequest(f.get(x), callback);
\r
493 public void finished(ReadGraph graph)
\r
494 throws DatabaseException {
\r
497 callback.finished(graph);
\r
501 public int hashCode() {
\r
502 return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
\r
505 public boolean equals(Object obj) {
\r
506 if(obj == this) return true;
\r
507 if(obj == null || obj.getClass() != getClass()) return false;
\r
508 Compose7<?, ?> other = (Compose7<?, ?>)obj;
\r
509 return f.equals(other.f) && g.equals(other.g);
\r
513 public static <X, Y> MultiRead<Y> compose(ParametrizedMultiRead<X, Y> f, MultiRead<X> g) {
\r
514 return new Compose7<X, Y>(f, g);
\r
517 // ------------------------------------------------------------------------
\r
519 private static class Compose8<X, Y, Z> implements ParametrizedMultiRead<X, Z> {
\r
520 final ParametrizedMultiRead<Y, Z> f;
\r
521 final ParametrizedMultiRead<X, Y> g;
\r
522 public Compose8(ParametrizedMultiRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
\r
526 public MultiRead<Z> get(X x) {
\r
527 return compose(f, g.get(x));
\r
530 public int hashCode() {
\r
531 return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
\r
534 public boolean equals(Object obj) {
\r
535 if(obj == this) return true;
\r
536 if(obj == null || obj.getClass() != getClass()) return false;
\r
537 Compose8<?, ?, ?> other = (Compose8<?, ?, ?>)obj;
\r
538 return f.equals(other.f) && g.equals(other.g);
\r
542 public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedMultiRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
\r
543 return new Compose8<X, Y, Z>(f, g);
\r
546 // ------------------------------------------------------------------------
\r
548 private static class Index<K, V> implements Read<Map<K, V>> {
\r
549 final MultiRead<V> values;
\r
550 final ParametrizedRead<V, K> keyOfValue;
\r
551 public Index(MultiRead<V> values, ParametrizedRead<V, K> keyOfValue) {
\r
552 this.values = values;
\r
553 this.keyOfValue = keyOfValue;
\r
556 public Map<K, V> perform(ReadGraph graph) throws DatabaseException {
\r
557 HashMap<K, V> result = new HashMap<K, V>();
\r
558 for(V value : graph.syncRequest(values))
\r
559 result.put(graph.syncRequest(keyOfValue.get(value)), value);
\r
563 public int hashCode() {
\r
564 return getClass().hashCode() + 31 * (values.hashCode() + 31 * keyOfValue.hashCode());
\r
567 public boolean equals(Object obj) {
\r
568 if(obj == this) return true;
\r
569 if(obj == null || obj.getClass() != getClass()) return false;
\r
570 Index<?, ?> other = (Index<?, ?>)obj;
\r
571 return values.equals(other.values) && keyOfValue.equals(other.keyOfValue);
\r
575 public static <K, V> Read<Map<K, V>> index(MultiRead<V> values, ParametrizedRead<V, K> keyOfValue) {
\r
576 return new Index<K, V>(values, keyOfValue);
\r
579 // ------------------------------------------------------------------------
\r
581 private static class Constant<T> implements Read<T> {
\r
583 public Constant(T value) {
\r
584 this.value = value;
\r
587 public T perform(ReadGraph graph) throws DatabaseException {
\r
591 public int hashCode() {
\r
592 return value == null ? 0 : value.hashCode();
\r
595 public boolean equals(Object obj) {
\r
598 if (obj == null || getClass() != obj.getClass())
\r
600 Constant<?> other = (Constant<?>) obj;
\r
601 return value == null ? other.value == null : value.equals(other.value);
\r
605 public static <T> Read<T> constant(T value) {
\r
606 return new Constant<T>(value);
\r
609 // ------------------------------------------------------------------------
\r
611 private static class Singleton<T> implements MultiRead<T> {
\r
613 public Singleton(T value) {
\r
614 this.value = value;
\r
617 public void perform(ReadGraph graph, AsyncMultiProcedure<T> callback)
\r
618 throws DatabaseException {
\r
619 callback.execute(graph, value);
\r
620 callback.finished(graph);
\r
623 public int hashCode() {
\r
624 return value.hashCode();
\r
627 public boolean equals(Object obj) {
\r
630 if (obj == null || getClass() != obj.getClass())
\r
632 Singleton<?> other = (Singleton<?>) obj;
\r
633 return value.equals(other.value);
\r
637 public static <T> MultiRead<T> singleton(T value) {
\r
638 return new Singleton<T>(value);
\r
641 // ------------------------------------------------------------------------
\r
643 private static class Name implements Read<String> {
\r
645 public Name(Resource resource) {
\r
646 this.resource = resource;
\r
649 public String perform(ReadGraph graph) throws DatabaseException {
\r
650 Layer0 L0 = Layer0.getInstance(graph);
\r
651 SynchronizationProcedure<String> procedure = new SynchronizationProcedure<String>();
\r
652 graph.forRelatedValue(resource, L0.HasName, procedure);
\r
653 return procedure.getResult();
\r
656 public int hashCode() {
\r
657 return getClass().hashCode() + 31 * resource.hashCode();
\r
660 public boolean equals(Object obj) {
\r
661 if(obj == this) return true;
\r
662 if(obj == null || obj.getClass() != getClass()) return false;
\r
663 Name other = (Name)obj;
\r
664 return resource.equals(other.resource);
\r
667 public static Read<String> name(Resource resource) {
\r
668 return new Name(resource);
\r
671 // ------------------------------------------------------------------------
\r
673 public static final ParametrizedRead<Resource, String> NAME = new ParametrizedRead<Resource, String>() {
\r
676 public Read<String> get(Resource resource) {
\r
677 return name(resource);
\r
682 // ------------------------------------------------------------------------
\r