]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/combinations/Combinators.java
Merge "Multiple reader thread support for db client"
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / request / combinations / Combinators.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.db.layer0.request.combinations;
13
14 import java.util.HashMap;
15 import java.util.Map;
16
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.common.request.ResourceRead;
21 import org.simantics.db.exception.DatabaseException;
22 import org.simantics.db.procedure.Procedure;
23 import org.simantics.db.procedure.SyncMultiProcedure;
24 import org.simantics.db.request.MultiRead;
25 import org.simantics.db.request.Read;
26 import org.simantics.layer0.Layer0;
27
28 /**
29  * Functions that create new read requests by combining simpler ones.
30  * @author Hannu Niemist�
31  */
32 public class Combinators {      
33                 
34         // ------------------------------------------------------------------------
35         
36         private static class Objects implements MultiRead<Resource> {
37                 Resource subject;               
38                 Resource relation;
39                 public Objects(Resource subject, Resource relation) {
40                         this.subject = subject;
41                         this.relation = relation;
42                 }
43                 @Override
44                 public void perform(ReadGraph graph,
45                                 SyncMultiProcedure<Resource> callback)
46                                 throws DatabaseException {
47                         for(Resource object : graph.getObjects(subject, relation)) {
48                                 callback.execute(graph, object);
49                         }
50                 }               
51             @Override
52             public int hashCode() {
53                 return subject.hashCode() + 31 * relation.hashCode();
54             }
55             @Override
56             public boolean equals(Object object) {
57                 if (this == object) return true;
58                 else if (object == null || getClass() != object.getClass()) return false;
59                 Objects other = (Objects)object;
60                 return subject.equals(other.subject) && relation.equals(other.relation);
61             }
62         }
63         
64         /**
65          * Returns a multi read request that reads the objects of given subject and relation. 
66          */
67         public static MultiRead<Resource> objects(Resource subject, Resource relation) {
68                 return new Objects(subject, relation);
69         }
70         
71         // ------------------------------------------------------------------------
72         
73         private static class Relation implements ParametrizedMultiRead<Resource, Resource> {
74                 Resource relation;
75                 public Relation(Resource relation) {
76                         this.relation = relation;
77                 }
78                 @Override
79                 public MultiRead<Resource> get(Resource subject) {
80                         return objects(subject, relation);
81                 }
82             @Override
83             public int hashCode() {
84                 return getClass().hashCode() + 31 * relation.hashCode();
85             }
86                 @Override
87                 public boolean equals(Object obj) {
88                         if(obj == this) return true;
89                         if(obj == null || obj.getClass() != getClass()) return false;
90                         Relation other = (Relation)obj;
91                         return relation.equals(other.relation);
92                 }
93         }
94         
95         /**
96          * Returns a function <code>subject -> objects(subject, relation)</code>. 
97          */
98         public static ParametrizedMultiRead<Resource,Resource> relation(Resource relation) {
99                 return new Relation(relation);
100         }
101         
102         // ------------------------------------------------------------------------
103         
104         public static class SynchronizationProcedure<T> implements Procedure<T> {
105                 T result;
106                 DatabaseException exception;
107                 boolean ready = false;
108                 @Override
109                 public synchronized void exception(Throwable t) {
110                         this.exception = 
111                                 t instanceof DatabaseException ? (DatabaseException)t : new DatabaseException(t);
112                         ready = true;
113                         notify();
114                 }
115                 @Override
116                 public synchronized void execute(T result) {
117                         this.result = result;
118                         ready = true;           
119                         notify();
120                 }               
121                 public synchronized T getResult() throws DatabaseException {
122                         if(!ready) {
123                                 try {
124                                         wait();
125                                 } catch (InterruptedException e) {
126                                         throw new DatabaseException(e);
127                                 }       
128                         }
129                         if(exception != null)
130                                 throw exception;
131                         return result;
132                 }
133         }
134         
135         private static class PossibleObject implements Read<Resource> {
136                 Resource subject;               
137                 Resource relation;
138                 public PossibleObject(Resource subject, Resource relation) {
139                         this.subject = subject;
140                         this.relation = relation;
141                 }
142                 @Override
143                 public Resource perform(ReadGraph graph) throws DatabaseException {
144                         return graph.getPossibleObject(subject, relation);
145                 }       
146             @Override
147             public int hashCode() {
148                 return subject.hashCode() + 31 * relation.hashCode();
149             }
150             @Override
151             public boolean equals(Object object) {
152                 if (this == object) return true;
153                 else if (object == null || getClass() != object.getClass()) return false;
154                 PossibleObject other = (PossibleObject)object;
155                 return subject.equals(other.subject) && relation.equals(other.relation);
156             }
157         }
158         
159         /**
160          * Returns a read request that reads an object possibly connected to the subject by the relation.
161          */
162         public static Read<Resource> possibleObject(Resource subject, Resource relation) {
163                 return new PossibleObject(subject, relation);
164         }
165         
166         // ------------------------------------------------------------------------
167         
168         private static class PartialFunction implements ParametrizedRead<Resource, Resource> {
169                 Resource relation;
170                 public PartialFunction(Resource relation) {
171                         this.relation = relation;
172                 }
173                 @Override
174                 public Read<Resource> get(Resource subject) {
175                         return possibleObject(subject, relation);
176                 }
177             @Override
178             public int hashCode() {
179                 return getClass().hashCode() + 31 * relation.hashCode();
180             }
181                 @Override
182                 public boolean equals(Object obj) {
183                         if(obj == this) return true;
184                         if(obj == null || obj.getClass() != getClass()) return false;
185                         PartialFunction other = (PartialFunction)obj;
186                         return relation.equals(other.relation);
187                 }
188         }
189         
190         /**
191          * Returns a function <code>subject -> possibleObject(subject, relation)</code>. 
192          */
193         public static ParametrizedRead<Resource,Resource> partialFunction(Resource relation) {
194                 return new PartialFunction(relation);
195         }
196         
197         // ------------------------------------------------------------------------
198         
199         private static class SingleObject implements Read<Resource> {
200                 Resource subject;               
201                 Resource relation;
202                 public SingleObject(Resource subject, Resource relation) {
203                         this.subject = subject;
204                         this.relation = relation;
205                 }
206                 @Override
207                 public Resource perform(ReadGraph graph) throws DatabaseException {
208                         return graph.getSingleObject(subject, relation);
209                 }       
210             @Override
211             public int hashCode() {
212                 return subject.hashCode() + 31 * relation.hashCode();
213             }
214             @Override
215             public boolean equals(Object object) {
216                 if (this == object) return true;
217                 else if (object == null || getClass() != object.getClass()) return false;
218                 SingleObject other = (SingleObject)object;
219                 return subject.equals(other.subject) && relation.equals(other.relation);
220             }
221         }
222         
223         /**
224          * Returns a read request that reads an object connected to the subject by the relation.
225          */
226         public static Read<Resource> singleObject(Resource subject, Resource relation) {
227                 return new SingleObject(subject, relation);
228         }
229         
230         // ------------------------------------------------------------------------
231         
232         private static class CompleteFunction implements ParametrizedRead<Resource, Resource> {
233                 Resource relation;
234                 public CompleteFunction(Resource relation) {
235                         this.relation = relation;
236                 }
237                 @Override
238                 public Read<Resource> get(Resource subject) {
239                         return singleObject(subject, relation);
240                 }
241             @Override
242             public int hashCode() {
243                 return getClass().hashCode() + 31 * relation.hashCode();
244             }
245                 @Override
246                 public boolean equals(Object obj) {
247                         if(obj == this) return true;
248                         if(obj == null || obj.getClass() != getClass()) return false;
249                         CompleteFunction other = (CompleteFunction)obj;
250                         return relation.equals(other.relation);
251                 }
252         }
253         
254         /**
255          * Returns a function <code>subject -> singleObject(subject, relation)</code>. 
256          */
257         public static ParametrizedRead<Resource,Resource> completeFunction(Resource relation) {
258                 return new CompleteFunction(relation);
259         }
260         
261         // ------------------------------------------------------------------------
262         
263         private static class Compose1<X, Y> implements Read<Y> {
264                 final ParametrizedRead<X, Y> f;
265                 final Read<X> g;                
266                 public Compose1(ParametrizedRead<X, Y> f, Read<X> g) {
267                         this.f = f;
268                         this.g = g;
269                 }
270                 @Override
271                 public Y perform(ReadGraph graph) throws DatabaseException {
272                         return graph.syncRequest(f.get(graph.syncRequest(g)));
273                 }               
274                 @Override
275                 public int hashCode() {
276                         return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
277                 }
278                 @Override
279                 public boolean equals(Object obj) {
280                         if(obj == this) return true;
281                         if(obj == null || obj.getClass() != getClass()) return false;
282                         Compose1<?, ?> other = (Compose1<?, ?>)obj;
283                         return f.equals(other.f) && g.equals(other.g);
284                 }
285         }
286         
287         public static <X, Y> Read<Y> compose(ParametrizedRead<X, Y> f, Read<X> g) {
288                 return new Compose1<X, Y>(f, g);
289         }
290
291         // ------------------------------------------------------------------------
292         
293         private static class Compose2<X, Y, Z> implements ParametrizedRead<X, Z> {
294                 final ParametrizedRead<Y, Z> f;
295                 final ParametrizedRead<X, Y> g;         
296                 public Compose2(ParametrizedRead<Y, Z> f, ParametrizedRead<X, Y> g) {
297                         this.f = f;
298                         this.g = g;
299                 }
300                 public Read<Z> get(X x) {
301                         return compose(f, g.get(x));
302                 }
303                 @Override
304                 public int hashCode() {
305                         return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
306                 }
307                 @Override
308                 public boolean equals(Object obj) {
309                         if(obj == this) return true;
310                         if(obj == null || obj.getClass() != getClass()) return false;
311                         Compose2<?, ?, ?> other = (Compose2<?, ?, ?>)obj;
312                         return f.equals(other.f) && g.equals(other.g);
313                 }
314         }
315         
316         public static <X, Y, Z> ParametrizedRead<X, Z> compose(ParametrizedRead<Y, Z> f, ParametrizedRead<X, Y> g) {
317                 return new Compose2<X, Y, Z>(f, g);
318         }
319         
320         // ------------------------------------------------------------------------
321         
322         private static class Compose3<X, Y> implements MultiRead<Y> {
323                 final ParametrizedRead<X, Y> f;
324                 final MultiRead<X> g;           
325                 public Compose3(ParametrizedRead<X, Y> f, MultiRead<X> g) {
326                         this.f = f;
327                         this.g = g;
328                 }
329                 public void perform(ReadGraph graph, final SyncMultiProcedure<Y> callback)      throws DatabaseException {
330                     try {
331                                 for(X x : graph.syncRequest(g))
332                                         callback.execute(graph, graph.syncRequest(f.get(x)));
333                                 callback.finished(graph);
334                         } catch(DatabaseException e) {
335                                 callback.exception(graph, e);
336                         }
337                         /*// Not sure if this is correct
338                    graph.syncRequest(g, new SyncMultiProcedure<X>() {
339                                 @Override
340                                 public void exception(ReadGraph graph, Throwable throwable)
341                                 throws DatabaseException {
342                                         callback.exception(graph, throwable);                                   
343                                 }
344                                 @Override
345                                 public void execute(ReadGraph graph, X x)
346                                 throws DatabaseException {
347                                         callback.execute(graph, graph.syncRequest(f.get(x)));
348                                 }
349                                 @Override
350                                 public void finished(ReadGraph graph)
351                                 throws DatabaseException {
352                                 }
353                         });
354                         callback.finished(graph);*/
355                 }                                       
356                 @Override
357                 public int hashCode() {
358                         return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
359                 }
360                 @Override
361                 public boolean equals(Object obj) {
362                         if(obj == this) return true;
363                         if(obj == null || obj.getClass() != getClass()) return false;
364                         Compose3<?, ?> other = (Compose3<?, ?>)obj;
365                         return f.equals(other.f) && g.equals(other.g);
366                 }
367         }
368         
369         public static <X, Y> MultiRead<Y> compose(ParametrizedRead<X, Y> f, MultiRead<X> g) {
370                 return new Compose3<X, Y>(f, g);
371         }
372         
373         // ------------------------------------------------------------------------
374         
375         private static class Compose4<X, Y, Z> implements ParametrizedMultiRead<X, Z> {
376                 final ParametrizedRead<Y, Z> f;
377                 final ParametrizedMultiRead<X, Y> g;            
378                 public Compose4(ParametrizedRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
379                         this.f = f;
380                         this.g = g;
381                 }
382                 public MultiRead<Z> get(X x) {
383                         return compose(f, g.get(x));
384                 }
385                 @Override
386                 public int hashCode() {
387                         return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
388                 }
389                 @Override
390                 public boolean equals(Object obj) {
391                         if(obj == this) return true;
392                         if(obj == null || obj.getClass() != getClass()) return false;
393                         Compose4<?, ?, ?> other = (Compose4<?, ?, ?>)obj;
394                         return f.equals(other.f) && g.equals(other.g);
395                 }
396         }
397         
398         public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
399                 return new Compose4<X, Y, Z>(f, g);
400         }
401
402         // ------------------------------------------------------------------------
403         
404         private static class Compose5<X, Y> implements MultiRead<Y> {
405                 final ParametrizedMultiRead<X, Y> f;
406                 final Read<X> g;                
407                 public Compose5(ParametrizedMultiRead<X, Y> f, Read<X> g) {
408                         this.f = f;
409                         this.g = g;
410                 }
411                 @Override
412                 public void perform(ReadGraph graph, SyncMultiProcedure<Y> callback)
413                                 throws DatabaseException {
414                         graph.syncRequest(f.get(graph.syncRequest(g)), callback);
415                 }
416                 @Override
417                 public int hashCode() {
418                         return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
419                 }
420                 @Override
421                 public boolean equals(Object obj) {
422                         if(obj == this) return true;
423                         if(obj == null || obj.getClass() != getClass()) return false;
424                         Compose5<?, ?> other = (Compose5<?, ?>)obj;
425                         return f.equals(other.f) && g.equals(other.g);
426                 }
427         }
428         
429         public static <X, Y> MultiRead<Y> compose(ParametrizedMultiRead<X, Y> f, Read<X> g) {
430                 return new Compose5<X, Y>(f, g);
431         }
432
433         // ------------------------------------------------------------------------
434         
435         private static class Compose6<X, Y, Z> implements ParametrizedMultiRead<X, Z> {
436                 final ParametrizedMultiRead<Y, Z> f;
437                 final ParametrizedRead<X, Y> g;         
438                 public Compose6(ParametrizedMultiRead<Y, Z> f, ParametrizedRead<X, Y> g) {
439                         this.f = f;
440                         this.g = g;
441                 }
442                 public MultiRead<Z> get(X x) {
443                         return compose(f, g.get(x));
444                 }
445                 @Override
446                 public int hashCode() {
447                         return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
448                 }
449                 @Override
450                 public boolean equals(Object obj) {
451                         if(obj == this) return true;
452                         if(obj == null || obj.getClass() != getClass()) return false;
453                         Compose6<?, ?, ?> other = (Compose6<?, ?, ?>)obj;
454                         return f.equals(other.f) && g.equals(other.g);
455                 }
456         }
457         
458         public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedMultiRead<Y, Z> f, ParametrizedRead<X, Y> g) {
459                 return new Compose6<X, Y, Z>(f, g);
460         }
461         
462         // ------------------------------------------------------------------------
463         
464         private static class Compose7<X, Y> implements MultiRead<Y> {
465                 final ParametrizedMultiRead<X, Y> f;
466                 final MultiRead<X> g;           
467                 public Compose7(ParametrizedMultiRead<X, Y> f, MultiRead<X> g) {
468                         this.f = f;
469                         this.g = g;
470                 }
471                 public void perform(ReadGraph graph, final SyncMultiProcedure<Y> callback)      throws DatabaseException {
472                     try {
473                                 for(X x : graph.syncRequest(g))
474                                         for(Y y : graph.syncRequest(f.get(x)))
475                                                 callback.execute(graph, y);
476                                 callback.finished(graph);
477                         } catch(DatabaseException e) {
478                                 callback.exception(graph, e);
479                         }
480                         /*// Not correct because inner syncRequest calls callback.finished 
481                     graph.syncRequest(g, new SyncMultiProcedure<X>() {
482                                 @Override
483                                 public void exception(ReadGraph graph, Throwable throwable)
484                                 throws DatabaseException {
485                                         callback.exception(graph, throwable);                                   
486                                 }
487                                 @Override
488                                 public void execute(ReadGraph graph, X x) throws DatabaseException {
489                                         graph.syncRequest(f.get(x), callback);
490                                 }
491                                 @Override
492                                 public void finished(ReadGraph graph)
493                                 throws DatabaseException {
494                                 }
495                         });
496                         callback.finished(graph);
497                         */
498                 }                                       
499                 @Override
500                 public int hashCode() {
501                         return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
502                 }
503                 @Override
504                 public boolean equals(Object obj) {
505                         if(obj == this) return true;
506                         if(obj == null || obj.getClass() != getClass()) return false;
507                         Compose7<?, ?> other = (Compose7<?, ?>)obj;
508                         return f.equals(other.f) && g.equals(other.g);
509                 }
510         }
511         
512         public static <X, Y> MultiRead<Y> compose(ParametrizedMultiRead<X, Y> f, MultiRead<X> g) {
513                 return new Compose7<X, Y>(f, g);
514         }
515         
516         // ------------------------------------------------------------------------
517         
518         private static class Compose8<X, Y, Z> implements ParametrizedMultiRead<X, Z> {
519                 final ParametrizedMultiRead<Y, Z> f;
520                 final ParametrizedMultiRead<X, Y> g;            
521                 public Compose8(ParametrizedMultiRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
522                         this.f = f;
523                         this.g = g;
524                 }
525                 public MultiRead<Z> get(X x) {
526                         return compose(f, g.get(x));
527                 }
528                 @Override
529                 public int hashCode() {
530                         return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
531                 }
532                 @Override
533                 public boolean equals(Object obj) {
534                         if(obj == this) return true;
535                         if(obj == null || obj.getClass() != getClass()) return false;
536                         Compose8<?, ?, ?> other = (Compose8<?, ?, ?>)obj;
537                         return f.equals(other.f) && g.equals(other.g);
538                 }
539         }
540         
541         public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedMultiRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
542                 return new Compose8<X, Y, Z>(f, g);
543         }       
544         
545         // ------------------------------------------------------------------------
546
547         private static class Index<K, V> implements Read<Map<K, V>> {
548                 final MultiRead<V> values;
549                 final ParametrizedRead<V, K> keyOfValue;
550                 public Index(MultiRead<V> values, ParametrizedRead<V, K> keyOfValue) {
551                         this.values = values;
552                         this.keyOfValue = keyOfValue;
553                 }
554                 @Override
555                 public Map<K, V> perform(ReadGraph graph) throws DatabaseException {
556                         HashMap<K, V> result = new HashMap<K, V>();
557                         for(V value : graph.syncRequest(values))
558                                 result.put(graph.syncRequest(keyOfValue.get(value)), value);
559                         return result;
560                 }
561                 @Override
562                 public int hashCode() {
563                         return getClass().hashCode() + 31 * (values.hashCode() + 31 * keyOfValue.hashCode());
564                 }
565                 @Override
566                 public boolean equals(Object obj) {
567                         if(obj == this) return true;
568                         if(obj == null || obj.getClass() != getClass()) return false;
569                         Index<?, ?> other = (Index<?, ?>)obj;
570                         return values.equals(other.values) && keyOfValue.equals(other.keyOfValue);
571                 }       
572         }
573         
574         public static <K, V> Read<Map<K, V>> index(MultiRead<V> values, ParametrizedRead<V, K> keyOfValue) {
575                 return new Index<K, V>(values, keyOfValue);
576         }
577         
578         // ------------------------------------------------------------------------
579
580         private static class Constant<T> implements Read<T> {
581                 T value;
582                 public Constant(T value) {
583                         this.value = value;
584                 }
585                 @Override
586                 public T perform(ReadGraph graph) throws DatabaseException {
587                         return value;
588                 }
589                 @Override
590                 public int hashCode() {
591                         return value == null ? 0 : value.hashCode();
592                 }
593                 @Override
594                 public boolean equals(Object obj) {
595                         if (this == obj)
596                                 return true;
597                         if (obj == null || getClass() != obj.getClass())
598                                 return false;
599                         Constant<?> other = (Constant<?>) obj;
600                         return value == null ? other.value == null : value.equals(other.value);
601                 }               
602         }
603         
604         public static <T> Read<T> constant(T value) {
605                 return new Constant<T>(value);
606         }
607         
608         // ------------------------------------------------------------------------
609
610         private static class Singleton<T> implements MultiRead<T> {
611                 T value;
612                 public Singleton(T value) {
613                         this.value = value;
614                 }
615                 @Override
616                 public void perform(ReadGraph graph, SyncMultiProcedure<T> callback)
617                                 throws DatabaseException {
618                         callback.execute(graph, value);
619                         callback.finished(graph);
620                 }
621                 @Override
622                 public int hashCode() {
623                         return value.hashCode();
624                 }
625                 @Override
626                 public boolean equals(Object obj) {
627                         if (this == obj)
628                                 return true;
629                         if (obj == null || getClass() != obj.getClass())
630                                 return false;
631                         Singleton<?> other = (Singleton<?>) obj;
632                         return value.equals(other.value);
633                 }       
634         }
635         
636         public static <T> MultiRead<T> singleton(T value) {
637                 return new Singleton<T>(value);
638         }
639         
640         // ------------------------------------------------------------------------
641         
642         private static class Name extends ResourceRead<String> {
643                 
644                 public Name(Resource resource) {
645                         super(resource);
646                 }
647                 
648                 @Override
649                 public String perform(ReadGraph graph) throws DatabaseException {
650                 Layer0 L0 = Layer0.getInstance(graph);
651                 return graph.getRelatedValue(resource, L0.HasName);
652                 }
653                 
654         }       
655         public static Read<String> name(Resource resource) {
656                 return new Name(resource);
657         }
658         
659         // ------------------------------------------------------------------------
660         
661         public static final ParametrizedRead<Resource, String> NAME = new ParametrizedRead<Resource, String>() {
662
663                 @Override
664                 public Read<String> get(Resource resource) {
665                         return name(resource);
666                 }
667                 
668         };
669         
670         // ------------------------------------------------------------------------
671         
672 }