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