]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
index 2fc619ec7cb1fb744065f70d352aa0a3d7bb0694..1eea49e26d466cf582e79bdd0b0245afd9bc96cb 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.db.layer0.request.combinations;\r
-\r
-import java.util.HashMap;\r
-import java.util.Map;\r
-\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.common.request.ParametrizedRead;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.procedure.AsyncMultiProcedure;\r
-import org.simantics.db.procedure.Procedure;\r
-import org.simantics.db.request.MultiRead;\r
-import org.simantics.db.request.Read;\r
-import org.simantics.layer0.Layer0;\r
-\r
-/**\r
- * Functions that create new read requests by combining simpler ones.\r
- * @author Hannu Niemist�\r
- */\r
-public class Combinators {     \r
-               \r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class Objects implements MultiRead<Resource> {\r
-               Resource subject;               \r
-               Resource relation;\r
-               public Objects(Resource subject, Resource relation) {\r
-                       this.subject = subject;\r
-                       this.relation = relation;\r
-               }\r
-               @Override\r
-               public void perform(ReadGraph graph,\r
-                               AsyncMultiProcedure<Resource> callback)\r
-                               throws DatabaseException {\r
-                       graph.forEachObject(subject, relation, callback);\r
-               }               \r
-           @Override\r
-           public int hashCode() {\r
-               return subject.hashCode() + 31 * relation.hashCode();\r
-           }\r
-           @Override\r
-           public boolean equals(Object object) {\r
-               if (this == object) return true;\r
-               else if (object == null || getClass() != object.getClass()) return false;\r
-               Objects other = (Objects)object;\r
-               return subject.equals(other.subject) && relation.equals(other.relation);\r
-           }\r
-       }\r
-       \r
-       /**\r
-        * Returns a multi read request that reads the objects of given subject and relation. \r
-        */\r
-       public static MultiRead<Resource> objects(Resource subject, Resource relation) {\r
-               return new Objects(subject, relation);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class Relation implements ParametrizedMultiRead<Resource, Resource> {\r
-               Resource relation;\r
-               public Relation(Resource relation) {\r
-                       this.relation = relation;\r
-               }\r
-               @Override\r
-               public MultiRead<Resource> get(Resource subject) {\r
-                       return objects(subject, relation);\r
-               }\r
-           @Override\r
-           public int hashCode() {\r
-               return getClass().hashCode() + 31 * relation.hashCode();\r
-           }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       Relation other = (Relation)obj;\r
-                       return relation.equals(other.relation);\r
-               }\r
-       }\r
-       \r
-       /**\r
-        * Returns a function <code>subject -> objects(subject, relation)</code>. \r
-        */\r
-       public static ParametrizedMultiRead<Resource,Resource> relation(Resource relation) {\r
-               return new Relation(relation);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       public static class SynchronizationProcedure<T> implements Procedure<T> {\r
-               T result;\r
-               DatabaseException exception;\r
-               boolean ready = false;\r
-               @Override\r
-               public synchronized void exception(Throwable t) {\r
-                       this.exception = \r
-                               t instanceof DatabaseException ? (DatabaseException)t : new DatabaseException(t);\r
-                       ready = true;\r
-                       notify();\r
-               }\r
-               @Override\r
-               public synchronized void execute(T result) {\r
-                       this.result = result;\r
-                       ready = true;           \r
-                       notify();\r
-               }               \r
-               public synchronized T getResult() throws DatabaseException {\r
-                       if(!ready) {\r
-                               try {\r
-                                       wait();\r
-                               } catch (InterruptedException e) {\r
-                                       throw new DatabaseException(e);\r
-                               }       \r
-                       }\r
-                       if(exception != null)\r
-                               throw exception;\r
-                       return result;\r
-               }\r
-       }\r
-       \r
-       private static class PossibleObject implements Read<Resource> {\r
-               Resource subject;               \r
-               Resource relation;\r
-               public PossibleObject(Resource subject, Resource relation) {\r
-                       this.subject = subject;\r
-                       this.relation = relation;\r
-               }\r
-               @Override\r
-               public Resource perform(ReadGraph graph) throws DatabaseException {\r
-                       SynchronizationProcedure<Resource> procedure = new SynchronizationProcedure<Resource>();\r
-                       graph.forPossibleObject(subject, relation, procedure);\r
-                       return procedure.getResult();\r
-               }       \r
-           @Override\r
-           public int hashCode() {\r
-               return subject.hashCode() + 31 * relation.hashCode();\r
-           }\r
-           @Override\r
-           public boolean equals(Object object) {\r
-               if (this == object) return true;\r
-               else if (object == null || getClass() != object.getClass()) return false;\r
-               PossibleObject other = (PossibleObject)object;\r
-               return subject.equals(other.subject) && relation.equals(other.relation);\r
-           }\r
-       }\r
-       \r
-       /**\r
-        * Returns a read request that reads an object possibly connected to the subject by the relation.\r
-        */\r
-       public static Read<Resource> possibleObject(Resource subject, Resource relation) {\r
-               return new PossibleObject(subject, relation);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class PartialFunction implements ParametrizedRead<Resource, Resource> {\r
-               Resource relation;\r
-               public PartialFunction(Resource relation) {\r
-                       this.relation = relation;\r
-               }\r
-               @Override\r
-               public Read<Resource> get(Resource subject) {\r
-                       return possibleObject(subject, relation);\r
-               }\r
-           @Override\r
-           public int hashCode() {\r
-               return getClass().hashCode() + 31 * relation.hashCode();\r
-           }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       PartialFunction other = (PartialFunction)obj;\r
-                       return relation.equals(other.relation);\r
-               }\r
-       }\r
-       \r
-       /**\r
-        * Returns a function <code>subject -> possibleObject(subject, relation)</code>. \r
-        */\r
-       public static ParametrizedRead<Resource,Resource> partialFunction(Resource relation) {\r
-               return new PartialFunction(relation);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class SingleObject implements Read<Resource> {\r
-               Resource subject;               \r
-               Resource relation;\r
-               public SingleObject(Resource subject, Resource relation) {\r
-                       this.subject = subject;\r
-                       this.relation = relation;\r
-               }\r
-               @Override\r
-               public Resource perform(ReadGraph graph) throws DatabaseException {\r
-                       SynchronizationProcedure<Resource> procedure = new SynchronizationProcedure<Resource>();\r
-                       graph.forSingleObject(subject, relation, procedure);\r
-                       return procedure.getResult();\r
-               }       \r
-           @Override\r
-           public int hashCode() {\r
-               return subject.hashCode() + 31 * relation.hashCode();\r
-           }\r
-           @Override\r
-           public boolean equals(Object object) {\r
-               if (this == object) return true;\r
-               else if (object == null || getClass() != object.getClass()) return false;\r
-               SingleObject other = (SingleObject)object;\r
-               return subject.equals(other.subject) && relation.equals(other.relation);\r
-           }\r
-       }\r
-       \r
-       /**\r
-        * Returns a read request that reads an object connected to the subject by the relation.\r
-        */\r
-       public static Read<Resource> singleObject(Resource subject, Resource relation) {\r
-               return new SingleObject(subject, relation);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class CompleteFunction implements ParametrizedRead<Resource, Resource> {\r
-               Resource relation;\r
-               public CompleteFunction(Resource relation) {\r
-                       this.relation = relation;\r
-               }\r
-               @Override\r
-               public Read<Resource> get(Resource subject) {\r
-                       return singleObject(subject, relation);\r
-               }\r
-           @Override\r
-           public int hashCode() {\r
-               return getClass().hashCode() + 31 * relation.hashCode();\r
-           }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       CompleteFunction other = (CompleteFunction)obj;\r
-                       return relation.equals(other.relation);\r
-               }\r
-       }\r
-       \r
-       /**\r
-        * Returns a function <code>subject -> singleObject(subject, relation)</code>. \r
-        */\r
-       public static ParametrizedRead<Resource,Resource> completeFunction(Resource relation) {\r
-               return new CompleteFunction(relation);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class Compose1<X, Y> implements Read<Y> {\r
-               final ParametrizedRead<X, Y> f;\r
-               final Read<X> g;                \r
-               public Compose1(ParametrizedRead<X, Y> f, Read<X> g) {\r
-                       this.f = f;\r
-                       this.g = g;\r
-               }\r
-               @Override\r
-               public Y perform(ReadGraph graph) throws DatabaseException {\r
-                       return graph.syncRequest(f.get(graph.syncRequest(g)));\r
-               }               \r
-               @Override\r
-               public int hashCode() {\r
-                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());\r
-               }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       Compose1<?, ?> other = (Compose1<?, ?>)obj;\r
-                       return f.equals(other.f) && g.equals(other.g);\r
-               }\r
-       }\r
-       \r
-       public static <X, Y> Read<Y> compose(ParametrizedRead<X, Y> f, Read<X> g) {\r
-               return new Compose1<X, Y>(f, g);\r
-       }\r
-\r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class Compose2<X, Y, Z> implements ParametrizedRead<X, Z> {\r
-               final ParametrizedRead<Y, Z> f;\r
-               final ParametrizedRead<X, Y> g;         \r
-               public Compose2(ParametrizedRead<Y, Z> f, ParametrizedRead<X, Y> g) {\r
-                       this.f = f;\r
-                       this.g = g;\r
-               }\r
-               public Read<Z> get(X x) {\r
-                       return compose(f, g.get(x));\r
-               }\r
-               @Override\r
-               public int hashCode() {\r
-                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());\r
-               }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       Compose2<?, ?, ?> other = (Compose2<?, ?, ?>)obj;\r
-                       return f.equals(other.f) && g.equals(other.g);\r
-               }\r
-       }\r
-       \r
-       public static <X, Y, Z> ParametrizedRead<X, Z> compose(ParametrizedRead<Y, Z> f, ParametrizedRead<X, Y> g) {\r
-               return new Compose2<X, Y, Z>(f, g);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class Compose3<X, Y> implements MultiRead<Y> {\r
-               final ParametrizedRead<X, Y> f;\r
-               final MultiRead<X> g;           \r
-               public Compose3(ParametrizedRead<X, Y> f, MultiRead<X> g) {\r
-                       this.f = f;\r
-                       this.g = g;\r
-               }\r
-               public void perform(ReadGraph graph, final AsyncMultiProcedure<Y> callback)     throws DatabaseException {\r
-                   try {\r
-                               for(X x : graph.syncRequest(g))\r
-                                       callback.execute(graph, graph.syncRequest(f.get(x)));\r
-                               callback.finished(graph);\r
-                       } catch(DatabaseException e) {\r
-                               callback.exception(graph, e);\r
-                       }\r
-                       /*// Not sure if this is correct\r
-                  graph.syncRequest(g, new SyncMultiProcedure<X>() {\r
-                               @Override\r
-                               public void exception(ReadGraph graph, Throwable throwable)\r
-                               throws DatabaseException {\r
-                                       callback.exception(graph, throwable);                                   \r
-                               }\r
-                               @Override\r
-                               public void execute(ReadGraph graph, X x)\r
-                               throws DatabaseException {\r
-                                       callback.execute(graph, graph.syncRequest(f.get(x)));\r
-                               }\r
-                               @Override\r
-                               public void finished(ReadGraph graph)\r
-                               throws DatabaseException {\r
-                               }\r
-                       });\r
-                       callback.finished(graph);*/\r
-               }                                       \r
-               @Override\r
-               public int hashCode() {\r
-                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());\r
-               }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       Compose3<?, ?> other = (Compose3<?, ?>)obj;\r
-                       return f.equals(other.f) && g.equals(other.g);\r
-               }\r
-       }\r
-       \r
-       public static <X, Y> MultiRead<Y> compose(ParametrizedRead<X, Y> f, MultiRead<X> g) {\r
-               return new Compose3<X, Y>(f, g);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class Compose4<X, Y, Z> implements ParametrizedMultiRead<X, Z> {\r
-               final ParametrizedRead<Y, Z> f;\r
-               final ParametrizedMultiRead<X, Y> g;            \r
-               public Compose4(ParametrizedRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {\r
-                       this.f = f;\r
-                       this.g = g;\r
-               }\r
-               public MultiRead<Z> get(X x) {\r
-                       return compose(f, g.get(x));\r
-               }\r
-               @Override\r
-               public int hashCode() {\r
-                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());\r
-               }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       Compose4<?, ?, ?> other = (Compose4<?, ?, ?>)obj;\r
-                       return f.equals(other.f) && g.equals(other.g);\r
-               }\r
-       }\r
-       \r
-       public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {\r
-               return new Compose4<X, Y, Z>(f, g);\r
-       }\r
-\r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class Compose5<X, Y> implements MultiRead<Y> {\r
-               final ParametrizedMultiRead<X, Y> f;\r
-               final Read<X> g;                \r
-               public Compose5(ParametrizedMultiRead<X, Y> f, Read<X> g) {\r
-                       this.f = f;\r
-                       this.g = g;\r
-               }\r
-               @Override\r
-               public void perform(ReadGraph graph, AsyncMultiProcedure<Y> callback)\r
-                               throws DatabaseException {\r
-                       graph.syncRequest(f.get(graph.syncRequest(g)), callback);\r
-               }\r
-               @Override\r
-               public int hashCode() {\r
-                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());\r
-               }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       Compose5<?, ?> other = (Compose5<?, ?>)obj;\r
-                       return f.equals(other.f) && g.equals(other.g);\r
-               }\r
-       }\r
-       \r
-       public static <X, Y> MultiRead<Y> compose(ParametrizedMultiRead<X, Y> f, Read<X> g) {\r
-               return new Compose5<X, Y>(f, g);\r
-       }\r
-\r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class Compose6<X, Y, Z> implements ParametrizedMultiRead<X, Z> {\r
-               final ParametrizedMultiRead<Y, Z> f;\r
-               final ParametrizedRead<X, Y> g;         \r
-               public Compose6(ParametrizedMultiRead<Y, Z> f, ParametrizedRead<X, Y> g) {\r
-                       this.f = f;\r
-                       this.g = g;\r
-               }\r
-               public MultiRead<Z> get(X x) {\r
-                       return compose(f, g.get(x));\r
-               }\r
-               @Override\r
-               public int hashCode() {\r
-                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());\r
-               }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       Compose6<?, ?, ?> other = (Compose6<?, ?, ?>)obj;\r
-                       return f.equals(other.f) && g.equals(other.g);\r
-               }\r
-       }\r
-       \r
-       public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedMultiRead<Y, Z> f, ParametrizedRead<X, Y> g) {\r
-               return new Compose6<X, Y, Z>(f, g);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class Compose7<X, Y> implements MultiRead<Y> {\r
-               final ParametrizedMultiRead<X, Y> f;\r
-               final MultiRead<X> g;           \r
-               public Compose7(ParametrizedMultiRead<X, Y> f, MultiRead<X> g) {\r
-                       this.f = f;\r
-                       this.g = g;\r
-               }\r
-               public void perform(ReadGraph graph, final AsyncMultiProcedure<Y> callback)     throws DatabaseException {\r
-                   try {\r
-                               for(X x : graph.syncRequest(g))\r
-                                       for(Y y : graph.syncRequest(f.get(x)))\r
-                                               callback.execute(graph, y);\r
-                               callback.finished(graph);\r
-                       } catch(DatabaseException e) {\r
-                               callback.exception(graph, e);\r
-                       }\r
-                       /*// Not correct because inner syncRequest calls callback.finished \r
-                   graph.syncRequest(g, new SyncMultiProcedure<X>() {\r
-                               @Override\r
-                               public void exception(ReadGraph graph, Throwable throwable)\r
-                               throws DatabaseException {\r
-                                       callback.exception(graph, throwable);                                   \r
-                               }\r
-                               @Override\r
-                               public void execute(ReadGraph graph, X x) throws DatabaseException {\r
-                                       graph.syncRequest(f.get(x), callback);\r
-                               }\r
-                               @Override\r
-                               public void finished(ReadGraph graph)\r
-                               throws DatabaseException {\r
-                               }\r
-                       });\r
-                       callback.finished(graph);\r
-                       */\r
-               }                                       \r
-               @Override\r
-               public int hashCode() {\r
-                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());\r
-               }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       Compose7<?, ?> other = (Compose7<?, ?>)obj;\r
-                       return f.equals(other.f) && g.equals(other.g);\r
-               }\r
-       }\r
-       \r
-       public static <X, Y> MultiRead<Y> compose(ParametrizedMultiRead<X, Y> f, MultiRead<X> g) {\r
-               return new Compose7<X, Y>(f, g);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class Compose8<X, Y, Z> implements ParametrizedMultiRead<X, Z> {\r
-               final ParametrizedMultiRead<Y, Z> f;\r
-               final ParametrizedMultiRead<X, Y> g;            \r
-               public Compose8(ParametrizedMultiRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {\r
-                       this.f = f;\r
-                       this.g = g;\r
-               }\r
-               public MultiRead<Z> get(X x) {\r
-                       return compose(f, g.get(x));\r
-               }\r
-               @Override\r
-               public int hashCode() {\r
-                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());\r
-               }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       Compose8<?, ?, ?> other = (Compose8<?, ?, ?>)obj;\r
-                       return f.equals(other.f) && g.equals(other.g);\r
-               }\r
-       }\r
-       \r
-       public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedMultiRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {\r
-               return new Compose8<X, Y, Z>(f, g);\r
-       }       \r
-       \r
-       // ------------------------------------------------------------------------\r
-\r
-       private static class Index<K, V> implements Read<Map<K, V>> {\r
-               final MultiRead<V> values;\r
-               final ParametrizedRead<V, K> keyOfValue;\r
-               public Index(MultiRead<V> values, ParametrizedRead<V, K> keyOfValue) {\r
-                       this.values = values;\r
-                       this.keyOfValue = keyOfValue;\r
-               }\r
-               @Override\r
-               public Map<K, V> perform(ReadGraph graph) throws DatabaseException {\r
-                       HashMap<K, V> result = new HashMap<K, V>();\r
-                       for(V value : graph.syncRequest(values))\r
-                               result.put(graph.syncRequest(keyOfValue.get(value)), value);\r
-                       return result;\r
-               }\r
-               @Override\r
-               public int hashCode() {\r
-                       return getClass().hashCode() + 31 * (values.hashCode() + 31 * keyOfValue.hashCode());\r
-               }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       Index<?, ?> other = (Index<?, ?>)obj;\r
-                       return values.equals(other.values) && keyOfValue.equals(other.keyOfValue);\r
-               }       \r
-       }\r
-       \r
-       public static <K, V> Read<Map<K, V>> index(MultiRead<V> values, ParametrizedRead<V, K> keyOfValue) {\r
-               return new Index<K, V>(values, keyOfValue);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-\r
-       private static class Constant<T> implements Read<T> {\r
-               T value;\r
-               public Constant(T value) {\r
-                       this.value = value;\r
-               }\r
-               @Override\r
-               public T perform(ReadGraph graph) throws DatabaseException {\r
-                       return value;\r
-               }\r
-               @Override\r
-               public int hashCode() {\r
-                       return value == null ? 0 : value.hashCode();\r
-               }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if (this == obj)\r
-                               return true;\r
-                       if (obj == null || getClass() != obj.getClass())\r
-                               return false;\r
-                       Constant<?> other = (Constant<?>) obj;\r
-                       return value == null ? other.value == null : value.equals(other.value);\r
-               }               \r
-       }\r
-       \r
-       public static <T> Read<T> constant(T value) {\r
-               return new Constant<T>(value);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-\r
-       private static class Singleton<T> implements MultiRead<T> {\r
-               T value;\r
-               public Singleton(T value) {\r
-                       this.value = value;\r
-               }\r
-               @Override\r
-               public void perform(ReadGraph graph, AsyncMultiProcedure<T> callback)\r
-                               throws DatabaseException {\r
-                       callback.execute(graph, value);\r
-                       callback.finished(graph);\r
-               }\r
-               @Override\r
-               public int hashCode() {\r
-                       return value.hashCode();\r
-               }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if (this == obj)\r
-                               return true;\r
-                       if (obj == null || getClass() != obj.getClass())\r
-                               return false;\r
-                       Singleton<?> other = (Singleton<?>) obj;\r
-                       return value.equals(other.value);\r
-               }       \r
-       }\r
-       \r
-       public static <T> MultiRead<T> singleton(T value) {\r
-               return new Singleton<T>(value);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       private static class Name implements Read<String> {\r
-               Resource resource;\r
-               public Name(Resource resource) {\r
-                       this.resource = resource;\r
-               }\r
-               @Override\r
-               public String perform(ReadGraph graph) throws DatabaseException {\r
-               Layer0 L0 = Layer0.getInstance(graph);\r
-                       SynchronizationProcedure<String> procedure = new SynchronizationProcedure<String>();\r
-                       graph.forRelatedValue(resource, L0.HasName, procedure);\r
-                       return procedure.getResult();\r
-               }\r
-           @Override\r
-           public int hashCode() {\r
-               return getClass().hashCode() + 31 * resource.hashCode();\r
-           }\r
-               @Override\r
-               public boolean equals(Object obj) {\r
-                       if(obj == this) return true;\r
-                       if(obj == null || obj.getClass() != getClass()) return false;\r
-                       Name other = (Name)obj;\r
-                       return resource.equals(other.resource);\r
-               }               \r
-       }       \r
-       public static Read<String> name(Resource resource) {\r
-               return new Name(resource);\r
-       }\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-       public static final ParametrizedRead<Resource, String> NAME = new ParametrizedRead<Resource, String>() {\r
-\r
-               @Override\r
-               public Read<String> get(Resource resource) {\r
-                       return name(resource);\r
-               }\r
-               \r
-       };\r
-       \r
-       // ------------------------------------------------------------------------\r
-       \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.db.layer0.request.combinations;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.request.ParametrizedRead;
+import org.simantics.db.common.request.ResourceRead;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.procedure.Procedure;
+import org.simantics.db.procedure.SyncMultiProcedure;
+import org.simantics.db.request.MultiRead;
+import org.simantics.db.request.Read;
+import org.simantics.layer0.Layer0;
+
+/**
+ * Functions that create new read requests by combining simpler ones.
+ * @author Hannu Niemist�
+ */
+public class Combinators {     
+               
+       // ------------------------------------------------------------------------
+       
+       private static class Objects implements MultiRead<Resource> {
+               Resource subject;               
+               Resource relation;
+               public Objects(Resource subject, Resource relation) {
+                       this.subject = subject;
+                       this.relation = relation;
+               }
+               @Override
+               public void perform(ReadGraph graph,
+                               SyncMultiProcedure<Resource> callback)
+                               throws DatabaseException {
+                       for(Resource object : graph.getObjects(subject, relation)) {
+                               callback.execute(graph, object);
+                       }
+               }               
+           @Override
+           public int hashCode() {
+               return subject.hashCode() + 31 * relation.hashCode();
+           }
+           @Override
+           public boolean equals(Object object) {
+               if (this == object) return true;
+               else if (object == null || getClass() != object.getClass()) return false;
+               Objects other = (Objects)object;
+               return subject.equals(other.subject) && relation.equals(other.relation);
+           }
+       }
+       
+       /**
+        * Returns a multi read request that reads the objects of given subject and relation. 
+        */
+       public static MultiRead<Resource> objects(Resource subject, Resource relation) {
+               return new Objects(subject, relation);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       private static class Relation implements ParametrizedMultiRead<Resource, Resource> {
+               Resource relation;
+               public Relation(Resource relation) {
+                       this.relation = relation;
+               }
+               @Override
+               public MultiRead<Resource> get(Resource subject) {
+                       return objects(subject, relation);
+               }
+           @Override
+           public int hashCode() {
+               return getClass().hashCode() + 31 * relation.hashCode();
+           }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       Relation other = (Relation)obj;
+                       return relation.equals(other.relation);
+               }
+       }
+       
+       /**
+        * Returns a function <code>subject -> objects(subject, relation)</code>. 
+        */
+       public static ParametrizedMultiRead<Resource,Resource> relation(Resource relation) {
+               return new Relation(relation);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       public static class SynchronizationProcedure<T> implements Procedure<T> {
+               T result;
+               DatabaseException exception;
+               boolean ready = false;
+               @Override
+               public synchronized void exception(Throwable t) {
+                       this.exception = 
+                               t instanceof DatabaseException ? (DatabaseException)t : new DatabaseException(t);
+                       ready = true;
+                       notify();
+               }
+               @Override
+               public synchronized void execute(T result) {
+                       this.result = result;
+                       ready = true;           
+                       notify();
+               }               
+               public synchronized T getResult() throws DatabaseException {
+                       if(!ready) {
+                               try {
+                                       wait();
+                               } catch (InterruptedException e) {
+                                       throw new DatabaseException(e);
+                               }       
+                       }
+                       if(exception != null)
+                               throw exception;
+                       return result;
+               }
+       }
+       
+       private static class PossibleObject implements Read<Resource> {
+               Resource subject;               
+               Resource relation;
+               public PossibleObject(Resource subject, Resource relation) {
+                       this.subject = subject;
+                       this.relation = relation;
+               }
+               @Override
+               public Resource perform(ReadGraph graph) throws DatabaseException {
+                       return graph.getPossibleObject(subject, relation);
+               }       
+           @Override
+           public int hashCode() {
+               return subject.hashCode() + 31 * relation.hashCode();
+           }
+           @Override
+           public boolean equals(Object object) {
+               if (this == object) return true;
+               else if (object == null || getClass() != object.getClass()) return false;
+               PossibleObject other = (PossibleObject)object;
+               return subject.equals(other.subject) && relation.equals(other.relation);
+           }
+       }
+       
+       /**
+        * Returns a read request that reads an object possibly connected to the subject by the relation.
+        */
+       public static Read<Resource> possibleObject(Resource subject, Resource relation) {
+               return new PossibleObject(subject, relation);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       private static class PartialFunction implements ParametrizedRead<Resource, Resource> {
+               Resource relation;
+               public PartialFunction(Resource relation) {
+                       this.relation = relation;
+               }
+               @Override
+               public Read<Resource> get(Resource subject) {
+                       return possibleObject(subject, relation);
+               }
+           @Override
+           public int hashCode() {
+               return getClass().hashCode() + 31 * relation.hashCode();
+           }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       PartialFunction other = (PartialFunction)obj;
+                       return relation.equals(other.relation);
+               }
+       }
+       
+       /**
+        * Returns a function <code>subject -> possibleObject(subject, relation)</code>. 
+        */
+       public static ParametrizedRead<Resource,Resource> partialFunction(Resource relation) {
+               return new PartialFunction(relation);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       private static class SingleObject implements Read<Resource> {
+               Resource subject;               
+               Resource relation;
+               public SingleObject(Resource subject, Resource relation) {
+                       this.subject = subject;
+                       this.relation = relation;
+               }
+               @Override
+               public Resource perform(ReadGraph graph) throws DatabaseException {
+                       return graph.getSingleObject(subject, relation);
+               }       
+           @Override
+           public int hashCode() {
+               return subject.hashCode() + 31 * relation.hashCode();
+           }
+           @Override
+           public boolean equals(Object object) {
+               if (this == object) return true;
+               else if (object == null || getClass() != object.getClass()) return false;
+               SingleObject other = (SingleObject)object;
+               return subject.equals(other.subject) && relation.equals(other.relation);
+           }
+       }
+       
+       /**
+        * Returns a read request that reads an object connected to the subject by the relation.
+        */
+       public static Read<Resource> singleObject(Resource subject, Resource relation) {
+               return new SingleObject(subject, relation);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       private static class CompleteFunction implements ParametrizedRead<Resource, Resource> {
+               Resource relation;
+               public CompleteFunction(Resource relation) {
+                       this.relation = relation;
+               }
+               @Override
+               public Read<Resource> get(Resource subject) {
+                       return singleObject(subject, relation);
+               }
+           @Override
+           public int hashCode() {
+               return getClass().hashCode() + 31 * relation.hashCode();
+           }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       CompleteFunction other = (CompleteFunction)obj;
+                       return relation.equals(other.relation);
+               }
+       }
+       
+       /**
+        * Returns a function <code>subject -> singleObject(subject, relation)</code>. 
+        */
+       public static ParametrizedRead<Resource,Resource> completeFunction(Resource relation) {
+               return new CompleteFunction(relation);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       private static class Compose1<X, Y> implements Read<Y> {
+               final ParametrizedRead<X, Y> f;
+               final Read<X> g;                
+               public Compose1(ParametrizedRead<X, Y> f, Read<X> g) {
+                       this.f = f;
+                       this.g = g;
+               }
+               @Override
+               public Y perform(ReadGraph graph) throws DatabaseException {
+                       return graph.syncRequest(f.get(graph.syncRequest(g)));
+               }               
+               @Override
+               public int hashCode() {
+                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
+               }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       Compose1<?, ?> other = (Compose1<?, ?>)obj;
+                       return f.equals(other.f) && g.equals(other.g);
+               }
+       }
+       
+       public static <X, Y> Read<Y> compose(ParametrizedRead<X, Y> f, Read<X> g) {
+               return new Compose1<X, Y>(f, g);
+       }
+
+       // ------------------------------------------------------------------------
+       
+       private static class Compose2<X, Y, Z> implements ParametrizedRead<X, Z> {
+               final ParametrizedRead<Y, Z> f;
+               final ParametrizedRead<X, Y> g;         
+               public Compose2(ParametrizedRead<Y, Z> f, ParametrizedRead<X, Y> g) {
+                       this.f = f;
+                       this.g = g;
+               }
+               public Read<Z> get(X x) {
+                       return compose(f, g.get(x));
+               }
+               @Override
+               public int hashCode() {
+                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
+               }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       Compose2<?, ?, ?> other = (Compose2<?, ?, ?>)obj;
+                       return f.equals(other.f) && g.equals(other.g);
+               }
+       }
+       
+       public static <X, Y, Z> ParametrizedRead<X, Z> compose(ParametrizedRead<Y, Z> f, ParametrizedRead<X, Y> g) {
+               return new Compose2<X, Y, Z>(f, g);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       private static class Compose3<X, Y> implements MultiRead<Y> {
+               final ParametrizedRead<X, Y> f;
+               final MultiRead<X> g;           
+               public Compose3(ParametrizedRead<X, Y> f, MultiRead<X> g) {
+                       this.f = f;
+                       this.g = g;
+               }
+               public void perform(ReadGraph graph, final SyncMultiProcedure<Y> callback)      throws DatabaseException {
+                   try {
+                               for(X x : graph.syncRequest(g))
+                                       callback.execute(graph, graph.syncRequest(f.get(x)));
+                               callback.finished(graph);
+                       } catch(DatabaseException e) {
+                               callback.exception(graph, e);
+                       }
+                       /*// Not sure if this is correct
+                  graph.syncRequest(g, new SyncMultiProcedure<X>() {
+                               @Override
+                               public void exception(ReadGraph graph, Throwable throwable)
+                               throws DatabaseException {
+                                       callback.exception(graph, throwable);                                   
+                               }
+                               @Override
+                               public void execute(ReadGraph graph, X x)
+                               throws DatabaseException {
+                                       callback.execute(graph, graph.syncRequest(f.get(x)));
+                               }
+                               @Override
+                               public void finished(ReadGraph graph)
+                               throws DatabaseException {
+                               }
+                       });
+                       callback.finished(graph);*/
+               }                                       
+               @Override
+               public int hashCode() {
+                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
+               }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       Compose3<?, ?> other = (Compose3<?, ?>)obj;
+                       return f.equals(other.f) && g.equals(other.g);
+               }
+       }
+       
+       public static <X, Y> MultiRead<Y> compose(ParametrizedRead<X, Y> f, MultiRead<X> g) {
+               return new Compose3<X, Y>(f, g);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       private static class Compose4<X, Y, Z> implements ParametrizedMultiRead<X, Z> {
+               final ParametrizedRead<Y, Z> f;
+               final ParametrizedMultiRead<X, Y> g;            
+               public Compose4(ParametrizedRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
+                       this.f = f;
+                       this.g = g;
+               }
+               public MultiRead<Z> get(X x) {
+                       return compose(f, g.get(x));
+               }
+               @Override
+               public int hashCode() {
+                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
+               }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       Compose4<?, ?, ?> other = (Compose4<?, ?, ?>)obj;
+                       return f.equals(other.f) && g.equals(other.g);
+               }
+       }
+       
+       public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
+               return new Compose4<X, Y, Z>(f, g);
+       }
+
+       // ------------------------------------------------------------------------
+       
+       private static class Compose5<X, Y> implements MultiRead<Y> {
+               final ParametrizedMultiRead<X, Y> f;
+               final Read<X> g;                
+               public Compose5(ParametrizedMultiRead<X, Y> f, Read<X> g) {
+                       this.f = f;
+                       this.g = g;
+               }
+               @Override
+               public void perform(ReadGraph graph, SyncMultiProcedure<Y> callback)
+                               throws DatabaseException {
+                       graph.syncRequest(f.get(graph.syncRequest(g)), callback);
+               }
+               @Override
+               public int hashCode() {
+                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
+               }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       Compose5<?, ?> other = (Compose5<?, ?>)obj;
+                       return f.equals(other.f) && g.equals(other.g);
+               }
+       }
+       
+       public static <X, Y> MultiRead<Y> compose(ParametrizedMultiRead<X, Y> f, Read<X> g) {
+               return new Compose5<X, Y>(f, g);
+       }
+
+       // ------------------------------------------------------------------------
+       
+       private static class Compose6<X, Y, Z> implements ParametrizedMultiRead<X, Z> {
+               final ParametrizedMultiRead<Y, Z> f;
+               final ParametrizedRead<X, Y> g;         
+               public Compose6(ParametrizedMultiRead<Y, Z> f, ParametrizedRead<X, Y> g) {
+                       this.f = f;
+                       this.g = g;
+               }
+               public MultiRead<Z> get(X x) {
+                       return compose(f, g.get(x));
+               }
+               @Override
+               public int hashCode() {
+                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
+               }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       Compose6<?, ?, ?> other = (Compose6<?, ?, ?>)obj;
+                       return f.equals(other.f) && g.equals(other.g);
+               }
+       }
+       
+       public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedMultiRead<Y, Z> f, ParametrizedRead<X, Y> g) {
+               return new Compose6<X, Y, Z>(f, g);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       private static class Compose7<X, Y> implements MultiRead<Y> {
+               final ParametrizedMultiRead<X, Y> f;
+               final MultiRead<X> g;           
+               public Compose7(ParametrizedMultiRead<X, Y> f, MultiRead<X> g) {
+                       this.f = f;
+                       this.g = g;
+               }
+               public void perform(ReadGraph graph, final SyncMultiProcedure<Y> callback)      throws DatabaseException {
+                   try {
+                               for(X x : graph.syncRequest(g))
+                                       for(Y y : graph.syncRequest(f.get(x)))
+                                               callback.execute(graph, y);
+                               callback.finished(graph);
+                       } catch(DatabaseException e) {
+                               callback.exception(graph, e);
+                       }
+                       /*// Not correct because inner syncRequest calls callback.finished 
+                   graph.syncRequest(g, new SyncMultiProcedure<X>() {
+                               @Override
+                               public void exception(ReadGraph graph, Throwable throwable)
+                               throws DatabaseException {
+                                       callback.exception(graph, throwable);                                   
+                               }
+                               @Override
+                               public void execute(ReadGraph graph, X x) throws DatabaseException {
+                                       graph.syncRequest(f.get(x), callback);
+                               }
+                               @Override
+                               public void finished(ReadGraph graph)
+                               throws DatabaseException {
+                               }
+                       });
+                       callback.finished(graph);
+                       */
+               }                                       
+               @Override
+               public int hashCode() {
+                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
+               }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       Compose7<?, ?> other = (Compose7<?, ?>)obj;
+                       return f.equals(other.f) && g.equals(other.g);
+               }
+       }
+       
+       public static <X, Y> MultiRead<Y> compose(ParametrizedMultiRead<X, Y> f, MultiRead<X> g) {
+               return new Compose7<X, Y>(f, g);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       private static class Compose8<X, Y, Z> implements ParametrizedMultiRead<X, Z> {
+               final ParametrizedMultiRead<Y, Z> f;
+               final ParametrizedMultiRead<X, Y> g;            
+               public Compose8(ParametrizedMultiRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
+                       this.f = f;
+                       this.g = g;
+               }
+               public MultiRead<Z> get(X x) {
+                       return compose(f, g.get(x));
+               }
+               @Override
+               public int hashCode() {
+                       return getClass().hashCode() + 31 * (f.hashCode() + 31 * g.hashCode());
+               }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       Compose8<?, ?, ?> other = (Compose8<?, ?, ?>)obj;
+                       return f.equals(other.f) && g.equals(other.g);
+               }
+       }
+       
+       public static <X, Y, Z> ParametrizedMultiRead<X, Z> compose(ParametrizedMultiRead<Y, Z> f, ParametrizedMultiRead<X, Y> g) {
+               return new Compose8<X, Y, Z>(f, g);
+       }       
+       
+       // ------------------------------------------------------------------------
+
+       private static class Index<K, V> implements Read<Map<K, V>> {
+               final MultiRead<V> values;
+               final ParametrizedRead<V, K> keyOfValue;
+               public Index(MultiRead<V> values, ParametrizedRead<V, K> keyOfValue) {
+                       this.values = values;
+                       this.keyOfValue = keyOfValue;
+               }
+               @Override
+               public Map<K, V> perform(ReadGraph graph) throws DatabaseException {
+                       HashMap<K, V> result = new HashMap<K, V>();
+                       for(V value : graph.syncRequest(values))
+                               result.put(graph.syncRequest(keyOfValue.get(value)), value);
+                       return result;
+               }
+               @Override
+               public int hashCode() {
+                       return getClass().hashCode() + 31 * (values.hashCode() + 31 * keyOfValue.hashCode());
+               }
+               @Override
+               public boolean equals(Object obj) {
+                       if(obj == this) return true;
+                       if(obj == null || obj.getClass() != getClass()) return false;
+                       Index<?, ?> other = (Index<?, ?>)obj;
+                       return values.equals(other.values) && keyOfValue.equals(other.keyOfValue);
+               }       
+       }
+       
+       public static <K, V> Read<Map<K, V>> index(MultiRead<V> values, ParametrizedRead<V, K> keyOfValue) {
+               return new Index<K, V>(values, keyOfValue);
+       }
+       
+       // ------------------------------------------------------------------------
+
+       private static class Constant<T> implements Read<T> {
+               T value;
+               public Constant(T value) {
+                       this.value = value;
+               }
+               @Override
+               public T perform(ReadGraph graph) throws DatabaseException {
+                       return value;
+               }
+               @Override
+               public int hashCode() {
+                       return value == null ? 0 : value.hashCode();
+               }
+               @Override
+               public boolean equals(Object obj) {
+                       if (this == obj)
+                               return true;
+                       if (obj == null || getClass() != obj.getClass())
+                               return false;
+                       Constant<?> other = (Constant<?>) obj;
+                       return value == null ? other.value == null : value.equals(other.value);
+               }               
+       }
+       
+       public static <T> Read<T> constant(T value) {
+               return new Constant<T>(value);
+       }
+       
+       // ------------------------------------------------------------------------
+
+       private static class Singleton<T> implements MultiRead<T> {
+               T value;
+               public Singleton(T value) {
+                       this.value = value;
+               }
+               @Override
+               public void perform(ReadGraph graph, SyncMultiProcedure<T> callback)
+                               throws DatabaseException {
+                       callback.execute(graph, value);
+                       callback.finished(graph);
+               }
+               @Override
+               public int hashCode() {
+                       return value.hashCode();
+               }
+               @Override
+               public boolean equals(Object obj) {
+                       if (this == obj)
+                               return true;
+                       if (obj == null || getClass() != obj.getClass())
+                               return false;
+                       Singleton<?> other = (Singleton<?>) obj;
+                       return value.equals(other.value);
+               }       
+       }
+       
+       public static <T> MultiRead<T> singleton(T value) {
+               return new Singleton<T>(value);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       private static class Name extends ResourceRead<String> {
+               
+               public Name(Resource resource) {
+                       super(resource);
+               }
+               
+               @Override
+               public String perform(ReadGraph graph) throws DatabaseException {
+               Layer0 L0 = Layer0.getInstance(graph);
+               return graph.getRelatedValue(resource, L0.HasName);
+               }
+               
+       }       
+       public static Read<String> name(Resource resource) {
+               return new Name(resource);
+       }
+       
+       // ------------------------------------------------------------------------
+       
+       public static final ParametrizedRead<Resource, String> NAME = new ParametrizedRead<Resource, String>() {
+
+               @Override
+               public Read<String> get(Resource resource) {
+                       return name(resource);
+               }
+               
+       };
+       
+       // ------------------------------------------------------------------------
+       
+}