]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/function/All.java
Fix handling of property variables with no predicate resource.
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / function / All.java
1 package org.simantics.db.layer0.function;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10 import java.util.concurrent.atomic.AtomicReference;
11
12 import org.simantics.databoard.Bindings;
13 import org.simantics.databoard.accessor.reference.ChildReference;
14 import org.simantics.databoard.accessor.reference.IndexReference;
15 import org.simantics.databoard.adapter.AdaptException;
16 import org.simantics.databoard.binding.Binding;
17 import org.simantics.databoard.binding.error.BindingConstructionException;
18 import org.simantics.databoard.binding.error.BindingException;
19 import org.simantics.databoard.binding.mutable.Variant;
20 import org.simantics.databoard.type.ArrayType;
21 import org.simantics.databoard.type.Datatype;
22 import org.simantics.databoard.type.NumberType;
23 import org.simantics.databoard.util.Range;
24 import org.simantics.db.Issue;
25 import org.simantics.db.ReadGraph;
26 import org.simantics.db.Resource;
27 import org.simantics.db.Statement;
28 import org.simantics.db.WriteGraph;
29 import org.simantics.db.common.issue.StandardIssue;
30 import org.simantics.db.common.primitiverequest.PossibleRelatedValueImplied2;
31 import org.simantics.db.common.primitiverequest.PossibleResource;
32 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
33 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
34 import org.simantics.db.common.request.IsEnumeratedValue;
35 import org.simantics.db.common.uri.UnescapedChildMapOfResource;
36 import org.simantics.db.common.utils.CommonDBUtils;
37 import org.simantics.db.common.utils.Functions;
38 import org.simantics.db.common.utils.ListUtils;
39 import org.simantics.db.common.utils.Logger;
40 import org.simantics.db.common.utils.NameUtils;
41 import org.simantics.db.common.utils.NearestOwnerFinder;
42 import org.simantics.db.common.validation.L0Validations;
43 import org.simantics.db.exception.AdaptionException;
44 import org.simantics.db.exception.DatabaseException;
45 import org.simantics.db.exception.DoesNotContainValueException;
46 import org.simantics.db.exception.NoSingleResultException;
47 import org.simantics.db.exception.RuntimeDatabaseException;
48 import org.simantics.db.layer0.exception.InvalidVariableException;
49 import org.simantics.db.layer0.exception.MissingVariableException;
50 import org.simantics.db.layer0.exception.MissingVariableValueException;
51 import org.simantics.db.layer0.exception.PendingVariableException;
52 import org.simantics.db.layer0.request.PossibleURI;
53 import org.simantics.db.layer0.request.PropertyInfo;
54 import org.simantics.db.layer0.request.PropertyInfoRequest;
55 import org.simantics.db.layer0.request.UnescapedAssertedPropertyMapOfResource;
56 import org.simantics.db.layer0.request.UnescapedMethodMapOfResource;
57 import org.simantics.db.layer0.request.UnescapedPropertyMapOfResource;
58 import org.simantics.db.layer0.scl.CompileResourceValueRequest;
59 import org.simantics.db.layer0.scl.CompileValueRequest;
60 import org.simantics.db.layer0.util.Layer0Utils;
61 import org.simantics.db.layer0.util.PrimitiveValueParser;
62 import org.simantics.db.layer0.variable.AbstractVariable;
63 import org.simantics.db.layer0.variable.ChildVariableMapRequest;
64 import org.simantics.db.layer0.variable.ExternalSetValue;
65 import org.simantics.db.layer0.variable.PropertyVariableMapRequest;
66 import org.simantics.db.layer0.variable.StandardAssertedGraphPropertyVariable;
67 import org.simantics.db.layer0.variable.StandardComposedProperty;
68 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
69 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
70 import org.simantics.db.layer0.variable.SubliteralPropertyVariable;
71 import org.simantics.db.layer0.variable.SubliteralPropertyVariableDeprecated;
72 import org.simantics.db.layer0.variable.ValueAccessor;
73 import org.simantics.db.layer0.variable.Variable;
74 import org.simantics.db.layer0.variable.VariableBuilder;
75 import org.simantics.db.layer0.variable.VariableMap;
76 import org.simantics.db.layer0.variable.VariableMapImpl;
77 import org.simantics.db.layer0.variable.VariableNode;
78 import org.simantics.db.layer0.variable.VariableNodeReadRunnable;
79 import org.simantics.db.layer0.variable.VariableUtils;
80 import org.simantics.db.layer0.variable.Variables;
81 import org.simantics.db.layer0.variable.Variables.NodeStructure;
82 import org.simantics.db.service.ClusteringSupport;
83 import org.simantics.db.service.UndoRedoSupport;
84 import org.simantics.issues.ontology.IssueResource;
85 import org.simantics.layer0.Layer0;
86 import org.simantics.scl.reflection.annotations.SCLValue;
87 import org.simantics.scl.runtime.SCLContext;
88 import org.simantics.scl.runtime.function.Function4;
89 import org.simantics.scl.runtime.function.FunctionImpl1;
90 import org.simantics.scl.runtime.function.FunctionImpl2;
91 import org.simantics.simulator.variable.exceptions.NodeManagerException;
92 import org.simantics.utils.Development;
93 import org.simantics.utils.datastructures.Pair;
94 import org.simantics.utils.strings.StringInputValidator;
95
96 import gnu.trove.map.hash.THashMap;
97 import gnu.trove.set.hash.THashSet;
98
99 public class All {
100
101         public static Object standardGetValue1(ReadGraph graph, Variable context) throws DatabaseException {
102
103                 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
104
105         // First from node
106         if(variable.node != null) {
107             Variant value = Variables.requestNodeValue(graph, variable.node);
108             if(Variables.PENDING_NODE_VALUE == value) throw new PendingVariableException("");
109             return value.getValue();
110         }
111                 
112                 try {
113
114             if(variable.property.hasEnumerationRange) {
115                         Resource object = variable.getRepresents(graph);
116                                 if(graph.sync(new IsEnumeratedValue(object))) {
117                             Layer0 L0 = Layer0.getInstance(graph);
118                                         if(graph.isInstanceOf(object, L0.Literal)) {
119                                                 return graph.getValue(object);
120                                         } else {
121                                                 String label = graph.getPossibleRelatedValue2(variable.getRepresents(graph), L0.HasLabel, Bindings.STRING);
122                                                 if(label == null) label = graph.getPossibleRelatedValue(variable.getRepresents(graph), L0.HasName, Bindings.STRING);
123                                                 if(label == null) label = "<no label>";
124                                                 return label;
125                                         }
126                                 }
127             }
128                         
129             if (variable.isAsserted()) {
130                                 if (variable.parentResource != null) {
131                                         Map<String, Pair<PropertyInfo, Resource>> assertions = graph.syncRequest(
132                                                         new UnescapedAssertedPropertyMapOfResource(variable.parentResource),
133                                                         TransientCacheAsyncListener.instance());
134
135                                         // NOTE: This optimization assumes the property
136                                         // variable's representation is the asserted object.
137                                         Resource object = variable.getPossibleRepresents(graph);
138                                         if (object != null) {
139                                                 return graph.getValue2(object, variable);
140                                         } else {
141                                                 for (Pair<PropertyInfo, Resource> assertion : assertions.values()) {
142                                                         if (assertion.first.predicate.equals(variable.getPossiblePredicateResource(graph))) {
143                                                                 return graph.getValue2(assertion.second, variable);
144                                                         }
145                                                 }
146                                         }
147                                 }
148             }
149                 
150                         return graph.getValue2(variable.getRepresents(graph), variable);
151                         
152                 } catch (NoSingleResultException e) {
153                         throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
154                 } catch (DoesNotContainValueException e) {
155                         throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
156                 } catch (DatabaseException e) {
157                         throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
158                 }
159
160         }
161         
162         public static Object standardGetValue2(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {           
163                 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
164
165         // First from node
166         if(variable.node != null) {
167             try {
168                 Variant value = Variables.requestNodeValue(graph, variable.node, binding);
169                 if(Variables.PENDING_NODE_VALUE == value) throw new PendingVariableException("");
170                 if(value == null) throw new MissingVariableValueException(variable.getPossibleURI(graph));
171                 return value.getValue(binding);
172             } catch (AdaptException e) {
173                 throw new AdaptionException("Could not get value for " + context.getURI(graph), e);
174             }
175         }
176                 
177         try {
178                         
179                 if(variable.property.hasEnumerationRange) {
180                 Resource object = variable.getRepresents(graph);
181                 if(graph.sync(new IsEnumeratedValue(object))) {
182                         Layer0 L0 = Layer0.getInstance(graph);
183                         if(graph.isInstanceOf(object, L0.Literal)) {
184                                 return graph.getValue(object, binding);
185                         } else {
186                                 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
187                         }
188                 }
189             }
190                         
191                 if (variable.isAsserted()) {
192                         if (variable.parentResource != null) {
193                                         Map<String, Pair<PropertyInfo, Resource>> assertions = graph.syncRequest(
194                                                         new UnescapedAssertedPropertyMapOfResource(variable.parentResource),
195                                                         TransientCacheAsyncListener.instance());
196
197                                         // NOTE: This optimization assumes the property
198                                         // variable's representation is the asserted object.
199                                         Resource object = variable.getPossibleRepresents(graph);
200                                         if (object != null) {
201                                                 return graph.getValue2(object, variable, binding);
202                                         } else {
203                                                 for (Pair<PropertyInfo, Resource> assertion : assertions.values()) {
204                                                         if (assertion.first.predicate.equals(variable.getPossiblePredicateResource(graph))) {
205                                                                 return graph.getValue2(assertion.second, variable, binding);
206                                                         }
207                                                 }
208                                         }
209                         }
210                 }
211                         
212                         return graph.getValue2(variable.getRepresents(graph), context, binding);
213                         
214                 } catch (NoSingleResultException e) {
215                         throw new MissingVariableValueException(variable.getPossibleURI(graph));
216                 } catch (DoesNotContainValueException e) {
217                         throw new MissingVariableValueException(variable.getPossibleURI(graph));
218                 } catch (DatabaseException e) {
219                         throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
220                 }
221
222         }
223
224         public static void standardSetValue2(WriteGraph graph, Variable context, final Object value) throws DatabaseException {
225                 
226             if(context instanceof StandardGraphPropertyVariable) {
227
228                 final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context; 
229                 
230                 // First from node
231             if(variable.node != null) {
232
233                 final Binding binding = Layer0Utils.getDefaultBinding(graph, variable);
234
235                 final AtomicReference<Object> oldValueRef = new AtomicReference<Object>();
236                 try {
237                     variable.node.support.manager.getRealm().syncExec(new Runnable() {
238                         @Override
239                         public void run() {
240                             try {
241                                 oldValueRef.set(getNodeValue(variable, binding));
242                                 setNodeValue(variable, value, binding);
243                             } catch (NodeManagerException e) {
244                                 throw new RuntimeException(e);
245                             } catch (BindingException e) {
246                                     throw new RuntimeException(e);
247                                 }
248                         }
249                     });
250                 } catch(RuntimeException e) {
251                     if(e.getCause() instanceof NodeManagerException || e.getCause() instanceof BindingException)
252                         throw new DatabaseException(e.getCause());
253                     else
254                         throw e;
255                 } catch (InterruptedException e) {
256                     throw new DatabaseException(e);
257                 }
258
259                 ExternalSetValue ext = new ExternalSetValue(variable.node.support.manager, variable.node.node,
260                         oldValueRef.get(), value, binding);
261                 graph.getService(UndoRedoSupport.class).addExternalOperation(graph, ext);
262
263                 return;
264             }
265                 
266             }
267             
268                 Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
269                 if(modifier == null) modifier = VariableUtils.defaultInputModifier; 
270                 try {
271                         modifier.apply(graph, context, value, Bindings.getBinding(value.getClass()));
272                 } catch (BindingConstructionException e) {
273                         throw new org.simantics.db.exception.BindingException("",e);
274                 }
275
276         }
277
278         public static void standardSetValue3(final WriteGraph graph, Variable context, final Object value, final Binding binding) throws DatabaseException {
279
280         // First from node
281         if(context instanceof StandardGraphPropertyVariable) {
282
283             final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context; 
284             
285             // First from node
286             if(variable.node != null) {
287                 
288                 try {
289                     
290                     variable.node.support.manager.getRealm().syncExec(new Runnable() {
291
292                         @Override
293                         public void run() {
294                             try {
295                                 Object oldValue = getNodeValue(variable, binding);
296                                 setNodeValue(variable, value, binding);
297                                 ExternalSetValue ext = new ExternalSetValue(variable.node.support.manager, variable.node.node, oldValue, value, binding);
298                                 graph.getService(UndoRedoSupport.class).addExternalOperation(graph, ext);
299                             } catch (NodeManagerException | BindingException e) {
300                                 Logger.defaultLogError(e);
301                             }
302                         }
303
304                         
305                     });
306                     
307                     return;
308                     
309                 } catch (InterruptedException e) {
310                     throw new DatabaseException(e);
311                 }
312                 
313             }
314             
315         }
316             
317                 Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
318                 if(modifier == null) modifier = VariableUtils.defaultInputModifier; 
319                 modifier.apply(graph, context, value, binding);
320
321         }
322
323         public static Datatype getDatatypeFromValue(ReadGraph graph, Variable context) throws DatabaseException {
324                 if (context instanceof AbstractVariable) {
325                         Binding defaultBinding = ((AbstractVariable)context).getPossibleDefaultBinding(graph);
326                         if (defaultBinding != null)
327                                 return defaultBinding.type();
328                 }
329                         
330         Variant value = context.getVariantValue(graph);
331         if (value.getBinding() == null)
332                 throw new DatabaseException("No value binding for " + context.getURI(graph));
333         
334         return value.getBinding().type();
335         }
336
337     @SuppressWarnings("rawtypes")
338     private static class DatatypeGetter implements VariableNodeReadRunnable {
339         final VariableNode node;
340         Datatype type;
341         Exception exception;
342
343         public DatatypeGetter(VariableNode node) {
344             this.node = node;
345         }
346
347         @SuppressWarnings("unchecked")
348         @Override
349         public void run() {
350             try {
351                 type = node.support.manager.getDatatype(node.node);
352             } catch (NodeManagerException e) {
353                 exception = e;
354             }
355         }
356         @Override
357         public String toString() {
358             return "DatatypeGetter(" + node.node + ")";
359         }
360     }
361
362     public static Datatype standardGetDatatype(ReadGraph graph, Variable context) throws DatabaseException {
363         if (context instanceof AbstractVariable) {
364                 final AbstractVariable variable = (AbstractVariable)context;
365                 if (variable.node != null) {
366                         try {
367                                 DatatypeGetter request = new DatatypeGetter(variable.node);
368                                 
369                                         variable.node.support.manager.getRealm().syncExec(request);
370                                         
371                                         if (request.exception != null)
372                                                 throw new DatabaseException(request.exception);
373                                         
374                                         return request.type;
375                                 } catch (InterruptedException e) {
376                                 }
377                 }
378         }
379         
380         return getDatatypeFromValue(graph, context);
381         }
382
383 //      @SCLValue(type = "ValueAccessor")
384 //      public static ValueAccessor standardValueAccessor = new ValueAccessor() {
385 //
386 //              @Override
387 //              public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
388 //                      return standardGetValue(graph, (StandardGraphPropertyVariable)context);
389 //              }
390 //
391 //              @Override
392 //              public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
393 //                      return standardGetValue(graph, context, binding);
394 //              }
395 //
396 //              @Override
397 //              public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
398 //                      standardSetValue(graph, context, value);
399 //              }
400 //
401 //              @Override
402 //              public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
403 //                      standardSetValue(graph, context, value, binding);
404 //              }
405 //
406 //              @Override
407 //              public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
408 //                      return standardGetDatatype(graph, context);
409 //              }
410 //              
411 //      };
412         
413         @SCLValue(type = "ValueAccessor")
414         public static ValueAccessor standardValueAccessor = new ValueAccessor() {
415
416                 @Override
417                 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
418                         ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
419                         if(accessor != null) return accessor.getValue(graph, context);
420                         else 
421                                 return standardGetValue1(graph, context);
422                 }
423
424                 @Override
425                 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
426                         ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
427                         if(accessor != null) return accessor.getValue(graph, context, binding);
428                         else 
429                                 return standardGetValue2(graph, context, binding);
430                 }
431
432                 @Override
433                 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
434                         ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
435                         if(accessor != null) accessor.setValue(graph, context, value);
436                         else 
437                                 standardSetValue2(graph, context, value);
438                 }
439
440                 @Override
441                 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
442                         ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
443                         if(accessor != null) accessor.setValue(graph, context, value, binding);
444                         else 
445                                 standardSetValue3(graph, context, value, binding);
446                 }
447
448                 @Override
449                 public Datatype getDatatype(ReadGraph graph, Variable context)
450                                 throws DatabaseException {
451                         ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
452                         if(accessor != null) return accessor.getDatatype(graph, context);
453                         else 
454                                 return standardGetDatatype(graph, context);
455                 }
456                 
457         };
458
459         public static Variable getStandardChildDomainPropertyVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
460         StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
461         PropertyInfo graphProperty = getPossiblePropertyInfoFromContext(graph, variable, variable.resource, name);
462         return getStandardChildDomainPropertyVariable(graph, context, graphProperty, name);
463     }
464
465     public static Resource getPossiblePropertyResource(ReadGraph graph, AbstractVariable parent, Object node) throws DatabaseException {
466         if(parent != null && parent.node != null && parent.node.node != null && parent.node.support != null) {
467             String propertyURI = getPossiblePropertyURI(parent, node);
468             if(propertyURI != null)
469                 return graph.getPossibleResource(propertyURI);
470         }
471         return null;
472     }
473
474         public static Variable getStandardChildDomainPropertyVariable(ReadGraph graph, Variable context, PropertyInfo graphProperty, String name) throws DatabaseException {
475         StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
476         Object propertyNode = getPossibleNodeProperty(graph, variable, name, true);
477         if(graphProperty != null && graphProperty.builder != null)
478             return buildPropertyVariable(graph, variable, variable.resource, graphProperty, propertyNode);
479         if(propertyNode != null) {
480             // Fallback: try to ask property resource uri from NodeManager
481             return createStandardGraphPropertyVariable(graph, variable, propertyNode);
482         }
483         // Final fallback: check types corresponding to
484         // node classification(s) and look for asserted
485         // properties from the URIs specified.
486         if (variable.node != null) {
487             try {
488                 @SuppressWarnings("unchecked")
489                 Set<String> classifications = variable.node.support.manager.getClassifications(variable.node.node);
490                 if (!classifications.isEmpty()) {
491                     for (String uri : classifications) {
492                         Resource type = graph.syncRequest(
493                                 new PossibleResource(uri),
494                                 TransientCacheAsyncListener.instance());
495                         if (type == null)
496                             continue;
497                         Map<String, Pair<PropertyInfo, Resource>> pm = graph.syncRequest(
498                                 new UnescapedAssertedPropertyMapOfResource(type),
499                                 TransientCacheAsyncListener.instance());
500                         Pair<PropertyInfo, Resource> pi = pm.get(name);
501                         if (pi != null) {
502                             return new StandardAssertedGraphPropertyVariable(graph, context, null, type, pi.first.predicate, pi.second);
503                         }
504                     }
505                 }
506             } catch(NodeManagerException e) {
507                 throw new DatabaseException(e);
508             }
509         }
510         return null;
511     }
512
513     public static Map<String, Variable> getStandardChildDomainPropertyVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
514         // Get properties with null identification
515         return getStandardChildDomainPropertyVariables(graph, context, null, map);
516     }
517
518     public static Map<String, Variable> getStandardChildDomainPropertyVariables(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
519         
520         StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
521         
522         Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
523         if(!nodeProperties.isEmpty()) {
524
525             // Get variables for properties read from the graph
526             Map<String,PropertyInfo> graphProperties = collectPropertyInfosFromContext(graph, variable, variable.resource);
527             
528             Set<String> used = new THashSet<String>(nodeProperties.size());
529             
530             map = ensureVariableMap(map, graphProperties.size() + nodeProperties.size());
531             
532             // Process NodeManager property nodes
533             for(Object nodeProperty : nodeProperties) {
534                 String name = getNodeName(variable, nodeProperty);
535                 used.add(name);
536                 
537                 PropertyInfo graphProperty = graphProperties.get(name); 
538                 if(graphProperty != null && graphProperty.builder != null) {
539                     if (classification != null && !graphProperty.hasClassification(classification)) continue;
540                     
541                     // Combine with identically named graph property
542                     map.put(name, buildPropertyVariable(graph, variable, variable.resource, graphProperty, nodeProperty));
543                     continue;
544                 }
545                 
546                 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
547             }
548             
549             // Process graph properties
550             for(PropertyInfo info : graphProperties.values()) {
551                 String name = info.name;
552                 if(used != null && used.contains(name)) continue;
553                 if (classification != null && !info.hasClassification(classification)) continue;
554                 if (info.builder != null) {
555                     map.put(name, buildPropertyVariable(graph, variable, variable.resource, info, null));
556                 }
557             }
558             return map;
559                 
560         } else {
561
562                 if(variable.resource == null) return map;
563
564                 // Only graph properties
565                 Collection<Resource> predicates = graph.getPredicates(variable.resource);
566                 if(predicates.isEmpty()) return map;
567                 
568                 map = ensureVariableMap(map, predicates.size());
569                 
570             // Process graph properties
571             for(Resource predicate : predicates) {
572                 
573                         PropertyInfo info = //graph.isImmutable(predicate) ?
574                                         graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance());// :
575                                                 //graph.syncRequest(new PropertyInfoRequest(predicate));
576
577                         if(!info.isHasProperty) continue;
578                                         
579                 if (classification != null && !info.hasClassification(classification)) continue;
580                 if (info.builder != null) {
581                     map.put(info.name, buildPropertyVariable(graph, variable, variable.resource, info, null));
582                 }
583                 
584             }
585             
586             return map;
587                 
588         }
589         
590      }
591         
592     @SCLValue(type = "VariableMap")
593         public static VariableMap standardChildDomainProperties = new VariableMapImpl() {
594         
595                 @Override
596                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
597                 return getStandardChildDomainPropertyVariable(graph, context, name);
598                 }
599
600                 @Override
601                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
602                     return getStandardChildDomainPropertyVariables(graph, context, map);
603                 }
604                 
605         };
606         
607     @SCLValue(type = "VariableMap")
608         public static VariableMap methodsPropertyDomainProperties = new VariableMapImpl() {
609         
610                 @Override
611                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
612                         Variable parent = context.getParent(graph);
613                         Resource container = parent.getPossibleRepresents(graph);
614                         if(container == null)
615                                 return null;
616                         Map<String,Resource> methods = graph.syncRequest(new UnescapedMethodMapOfResource(container));
617                         Resource predicate = methods.get(name);
618                         if(predicate != null) {
619                                 Layer0 L0 = Layer0.getInstance(graph);
620                                 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(L0.Entity_method));
621                                 Resource value = graph.getSingleObject(container, predicate);
622                                 return new StandardGraphPropertyVariable(context, null, container, info, value);
623                         }
624                         return null;
625                 }
626
627                 @Override
628                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
629                         Variable parent = context.getParent(graph);
630                         Resource container = parent.getPossibleRepresents(graph);
631                         if(container == null)
632                                 return Collections.emptyMap();
633                         Map<String,Resource> methods = graph.syncRequest(new UnescapedMethodMapOfResource(container));
634                         for(Map.Entry<String, Resource> entry : methods.entrySet()) {
635                                 String name = entry.getKey();
636                                 Resource predicate = entry.getValue();
637                                 Layer0 L0 = Layer0.getInstance(graph);
638                                 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(L0.Entity_method));
639                                 Resource value = graph.getSingleObject(container, predicate);
640                                 if(map == null) map = new HashMap<>();
641                                 map.put(name, new StandardGraphPropertyVariable(context, null, container, info, value));
642                         }
643                         return map;
644                 }
645                 
646         };
647
648         public static Variable getStandardPropertyDomainPropertyVariableFromValue(ReadGraph graph, Variable context, String name) throws DatabaseException {
649
650                 if(context instanceof StandardGraphPropertyVariable) {
651                 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
652                 Resource literal = variable.getPossibleRepresents(graph);
653                 Object propertyNode = getPossibleNodeProperty(graph, variable, name, false);
654
655                 if(literal != null) {
656                         Variable result = getPossiblePropertyFromContext(graph, variable, literal, name, propertyNode);
657                         if(result != null) return result;
658                 }
659                 
660                 Variable result = getPossibleSubliteralPropertyFromContext(graph, variable, name);
661                 if(result != null) return result;
662                 result = getPossiblePropertyFromContext(graph, variable, variable.property.predicate, name, propertyNode);
663                 if (result != null) return result;
664                 
665                 // Get possible property from NodeManager
666                 if (propertyNode != null)
667                         return createStandardGraphPropertyVariable(graph, variable, propertyNode);
668                 return null;
669                 } else if (context instanceof StandardGraphChildVariable) {
670                         return standardChildDomainProperties.getVariable(graph, context, name);
671                 } else {
672                         throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
673                 }                       
674                 
675         }
676         
677         public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
678
679                 if(context instanceof StandardGraphPropertyVariable) {
680                         StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
681                         map = collectPropertiesFromContext(graph, variable, variable.property.predicate, map);
682                         if (variable.parentResource != null) {
683                                 Resource literal = graph.getPossibleObject(variable.parentResource, variable.property.predicate);
684                                 if(literal != null) map=collectPropertiesFromContext(graph, variable, literal, map);
685                                 map=collectSubliteralProperties(graph, variable, map);
686                         }
687
688                         // Get properties from VariableNode
689                         map = getStandardNodePropertyVariables(graph, context, map);
690                         return map;
691                 } else if (context instanceof StandardGraphChildVariable) {
692                         return standardChildDomainProperties.getVariables(graph, context, map);
693                 } else {
694                         throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
695                 }
696                 
697         }
698         
699         public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
700
701                 if(context instanceof StandardGraphPropertyVariable) {
702                         StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
703                         map = collectPropertiesFromContext(graph, variable, variable.property.predicate, classification, map);
704                         if (variable.parentResource != null) {
705                                 Resource literal = graph.getPossibleObject(variable.parentResource, variable.property.predicate);
706                                 if(literal != null) map=collectPropertiesFromContext(graph, variable, literal, classification, map);
707                         }
708                         
709                         // Get properties from VariableNode
710                         map = getStandardNodePropertyVariables(graph, context, map);
711                         return map;
712                 } else if (context instanceof StandardGraphChildVariable) {
713                         return standardChildDomainProperties.getVariables(graph, context, map);
714                 } else {
715                         throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
716                 }       
717                 
718         }       
719         
720     @SCLValue(type = "VariableMap")
721         public static VariableMap standardPropertyDomainProperties = new VariableMapImpl() {
722
723         VariableMap getValueVariableMap(ReadGraph graph, Variable context) throws DatabaseException {
724                 Resource represents = context.getPossibleRepresents(graph);
725                 if(represents == null) return null;
726                 
727                 VariableMap map = graph.isImmutable(represents) ?
728                                 graph.syncRequest(new PropertyVariableMapRequest(represents), TransientCacheListener.<VariableMap>instance()) :
729                                         (VariableMap)graph.getPossibleRelatedValue2(represents, Layer0.getInstance(graph).domainProperties, represents);
730                 
731                 if(map == standardPropertyDomainProperties) return null;
732                 else return map;
733                 
734         }
735         
736                 @Override
737                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
738                         VariableMap valueMap = getValueVariableMap(graph, context);
739                         if(valueMap != null) return valueMap.getVariable(graph, context, name);
740                         return getStandardPropertyDomainPropertyVariableFromValue(graph, context, name);
741                 }
742
743                 @Override
744                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
745                         VariableMap valueMap = getValueVariableMap(graph, context);
746                         if(valueMap != null) return valueMap.getVariables(graph, context, map);
747                         else return getStandardPropertyDomainPropertyVariablesFromValue(graph, context, map);
748                 }
749                 
750                 @Override
751                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
752                         VariableMap valueMap = getValueVariableMap(graph, context);
753                         if(valueMap != null) return valueMap.getVariables(graph, context, classification, map);
754                         else return getStandardPropertyDomainPropertyVariablesFromValue(graph, context, classification, map);
755                 }
756                 
757         };
758
759     public static Resource getPossibleGraphChild(ReadGraph graph, Variable variable, String name) throws DatabaseException {
760         Resource resource = variable.getPossibleRepresents(graph);
761         if(resource == null) return null;
762         Map<String, Resource> graphChildren = graph.syncRequest(new UnescapedChildMapOfResource(resource));
763         return graphChildren.get(name);
764     }
765
766     public static Map<String,Resource> getPossibleGraphChildren(ReadGraph graph, Variable variable) throws DatabaseException {
767         Resource resource = variable.getPossibleRepresents(graph);
768         if(resource == null) return Collections.emptyMap();
769         return graph.syncRequest(new UnescapedChildMapOfResource(resource));
770     }
771
772     public static Object getPossibleNodeChild(ReadGraph graph, Variable variable, String name) throws DatabaseException {
773         if (!(variable instanceof AbstractVariable)) return null;
774         VariableNode<?> node = ((AbstractVariable)variable).node;
775         if(node == null) return null;
776         NodeStructure structure = Variables.requestNodeStructure(graph, node);
777         if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
778         return structure.children.get(name);
779         }
780         
781     public static Collection<Object> getPossibleNodeChildren(ReadGraph graph, Variable variable) throws DatabaseException {
782         if (!(variable instanceof AbstractVariable)) return null;
783         VariableNode<?> node = ((AbstractVariable)variable).node;
784         if(node == null) return Collections.emptyList();
785         NodeStructure structure = Variables.requestNodeStructure(graph, node);
786         if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
787         return structure.children.values();
788     }
789     
790     public static Object getPossibleNodeProperty(ReadGraph graph, Variable variable, String name, boolean throwPending) throws DatabaseException {
791         if (!(variable instanceof AbstractVariable)) return null;
792         VariableNode<?> node = ((AbstractVariable)variable).node;
793         if(node == null) return null;
794         NodeStructure structure = Variables.requestNodeStructure(graph, node);
795         if(throwPending && Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
796         return structure.properties.get(name);
797     }
798     
799     public static Collection<Object> getPossibleNodeProperties(ReadGraph graph, Variable variable) throws DatabaseException {
800         if (!(variable instanceof AbstractVariable)) return null;
801         VariableNode<?> node = ((AbstractVariable)variable).node;
802         if(node == null) return Collections.emptyList();
803         NodeStructure structure = Variables.requestNodeStructure(graph, node);
804         if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
805         return structure.properties.values();
806     }
807
808     @SuppressWarnings({ "rawtypes", "unchecked" })
809     public static VariableNode build(VariableNode parent, Object node) {
810         if(node == null) return null;
811         return new VariableNode(parent.support, node);
812     }
813
814     @Deprecated
815     public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
816         return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
817     }
818
819     @Deprecated
820     public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, Resource graphChild, String name) throws DatabaseException {
821         return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, graphChild, name);
822     }
823         
824     @Deprecated
825     public static Map<String, Variable> getStandardChildDomainChildVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
826         return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
827     }
828
829     @Deprecated
830     public static Map<String, Variable> getStandardChildDomainChildVariables(ReadGraph graph, Variable context, Map<String,Resource> graphChildren, Map<String, Variable> map) throws DatabaseException {
831         return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, graphChildren, map);
832     }
833     
834     /**
835      * Get a map of child Variables from a node manager-based Variable, combined with the existing variables in #map.
836      * @param graph  The read graph.
837      * @param context  The parent Variable.
838      * @param map  A map of variables into which the new variables are merged.
839      * @return  A map from variable names to instances
840      * @throws DatabaseException
841      */
842     public static Map<String, Variable> getStandardNodeChildVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
843         AbstractVariable variable = (AbstractVariable)context;
844         if (variable.node == null) return map;
845         
846         Collection<Object> nodeChildren = getPossibleNodeChildren(graph, variable);
847         if (nodeChildren.isEmpty()) return map;
848         
849         map = ensureVariableMap(map, nodeChildren.size());
850
851         for(Object nodeChild : nodeChildren) {
852             String name = getNodeName(variable, nodeChild);
853             if (!map.containsKey(name))
854                 map.put(name, createStandardGraphChildVariable(variable, nodeChild));
855         }
856
857         return map;
858     }
859
860     /**
861      * Get a map of property Variables from a node manager-based Variable, combined with the existing variables in #map.
862      * @param graph  The read graph.
863      * @param context  The parent Variable.
864      * @param map  A map of variables into which the new variables are merged.
865      * @return  A map from variable names to instances
866      * @throws DatabaseException
867      */
868     public static Map<String, Variable> getStandardNodePropertyVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
869         AbstractVariable variable = (AbstractVariable)context;
870         if (variable.node == null) return map;
871         
872         Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
873         if (nodeProperties.isEmpty()) return map;
874         
875         map = ensureVariableMap(map, nodeProperties.size());
876
877         for(Object nodeProperty : nodeProperties) {
878             String name = getNodeName(variable, nodeProperty);
879             if (!map.containsKey(name)) {
880                 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
881             }
882         }
883
884         return map;
885     }    
886
887         @SCLValue(type = "VariableMap")
888         public static VariableMap standardChildDomainChildren = new VariableMapImpl() {
889
890                 @Override
891                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
892                         return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
893                 }
894
895                 @Override
896                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
897                     return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
898                 }
899                 
900         };
901
902     @SCLValue(type = "VariableMap")
903         public static VariableMap standardPropertyDomainChildren = new VariableMapImpl() {
904
905         /**
906          * Get a possible non-standard VariableMap defined in the graph.
907          * @param graph  The graph
908          * @param context  The context node
909          * @return  A non-standard VariableMap instance for the context node,
910          *          or null, if not defined or defined as this instance.
911          * @throws DatabaseException
912          */
913         VariableMap getValueVariableMap(ReadGraph graph, Variable context) throws DatabaseException {
914                 Resource represents = context.getPossibleRepresents(graph);
915                 if(represents == null) return null;
916                         VariableMap map = graph.syncRequest(new ChildVariableMapRequest(represents));
917                 if(map == standardPropertyDomainChildren) return null;
918                 else return map;
919         }
920         
921                 @Override
922                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
923                         // Delegate call to a non-standard variable map?
924                         VariableMap valueMap = getValueVariableMap(graph, context);
925                         if(valueMap != null) return valueMap.getVariable(graph, context, name);
926                         
927                         if(context instanceof StandardGraphPropertyVariable) {
928                                 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
929                                 Datatype dt = variable.getDatatype(graph);
930                                 if (dt instanceof ArrayType) {
931                                         ChildReference ref = getPossibleIndexReference(name);
932                                         if (ref != null)
933                                                 return new SubliteralPropertyVariableDeprecated(variable, ref);
934                                 }
935                                 
936                                 // Check for a child node provided by the NodeManager
937                                 if (variable.node != null) {
938                                         Object childNode = getPossibleNodeChild(graph, variable, name);
939                                         if (childNode != null)
940                                                 return createStandardGraphChildVariable(variable, childNode);
941                                 }
942                                 return standardChildDomainChildren.getVariable(graph, context, name);
943                         } else if (context instanceof StandardGraphChildVariable) {
944                                 return standardChildDomainChildren.getVariable(graph, context, name);
945                         } else {
946                                 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
947                         }
948                 }
949
950                 @Override
951                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
952                         // Delegate call to a non-standard variable map?
953                         VariableMap valueMap = getValueVariableMap(graph, context);
954                         if(valueMap != null) return valueMap.getVariables(graph, context, map);
955                         
956                         if(context instanceof StandardGraphPropertyVariable) {
957                                 // Get child variables provided by the NodeManager
958                                 Map<String, Variable> result = getStandardNodeChildVariables(graph, context, map); 
959                                 return standardChildDomainChildren.getVariables(graph, context, result);
960                         } else if (context instanceof StandardGraphChildVariable) {
961                                 return standardChildDomainChildren.getVariables(graph, context, map);
962                         } else {
963                                 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
964                         }       
965                 }
966                 
967         };
968         
969         protected static ChildReference getPossibleIndexReference(String name) {
970                 if (name.startsWith("i-")) {
971                     try {
972                         int index = Integer.parseInt(name.substring(2));
973                         return new IndexReference(index);
974                     } catch (NumberFormatException e) {}
975                 }
976                 return null;
977         }
978
979         protected static ValueAccessor getPossiblePropertyValueAccessor(ReadGraph graph, StandardGraphPropertyVariable variable) throws DatabaseException {
980             if(variable.property == null) return null;
981             return variable.property.valueAccessor;
982 //        return graph.syncRequest(new PropertyValueAccessorRequest(variable.property), TransientCacheAsyncListener.<ValueAccessor>instance());
983 //              return graph.syncRequest(new PossibleRelatedValueImplied2<ValueAccessor>(variable.property, Layer0.getInstance(graph).valueAccessor));
984         }
985
986         public static ValueAccessor getPossibleValueValueAccessor(ReadGraph graph, Variable variable) throws DatabaseException {
987             Resource value = variable.getPossibleRepresents(graph);
988             if(value == null) return null;
989             //return graph.syncRequest(new PropertyValueAccessorRequest(value));
990                 return graph.syncRequest(new PossibleRelatedValueImplied2<ValueAccessor>(value, Layer0.getInstance(graph).valueAccessor));      
991         }
992         
993         public static PropertyInfo getPossiblePropertyInfoFromContext(ReadGraph graph, Variable variable, Resource context, String name) throws DatabaseException {
994             if(context == null) return null;
995                 Map<String, PropertyInfo> predicates = graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheListener.instance());
996                 return predicates.get(name);
997         }
998
999     public static Variable getPossiblePropertyFromContext(ReadGraph graph, Variable variable, Resource context, String name, Object propertyNode) throws DatabaseException {
1000         PropertyInfo info = getPossiblePropertyInfoFromContext(graph, variable, context, name);
1001         if(info == null || info.builder == null) return null;
1002         return buildPropertyVariable(graph, variable, context, info, propertyNode);
1003     }
1004     
1005     public static Variable getPossibleSubliteralPropertyFromContext(ReadGraph graph, StandardGraphPropertyVariable variable, String name) throws DatabaseException {
1006         
1007                 Resource predicate = variable.property.predicate;
1008                 if(predicate == null) return null;
1009
1010         PropertyInfo info = getPropertyInfo(graph, predicate);
1011         Pair<Resource, ChildReference> p = info.subliteralPredicates.get(name);
1012         if(p == null) return null;
1013         
1014                 return new SubliteralPropertyVariable(graph, variable, p.first, p.second);
1015         
1016     }
1017
1018     public static Map<String, PropertyInfo> collectPropertyInfosFromContext(ReadGraph graph, Variable variable, Resource context) throws DatabaseException {
1019         if(context == null) return Collections.emptyMap();
1020                 return graph.isImmutable(context) ?
1021                                 graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance()) :
1022                                 graph.syncRequest(new UnescapedPropertyMapOfResource(context));
1023     }
1024
1025         public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, Map<String, Variable> map) throws DatabaseException {
1026
1027                 Map<String,PropertyInfo> properties = graph.isImmutable(context) ?
1028                                 graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance()) :
1029                                 graph.syncRequest(new UnescapedPropertyMapOfResource(context));
1030                                 
1031                 if(properties.isEmpty()) return map;
1032                 
1033                 map = ensureVariableMap(map, properties.size());
1034                 
1035                 for(PropertyInfo info : properties.values()) {
1036                         String name = info.name;
1037                         if (info.builder != null) {
1038                                 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1039                                 map.put(name, v);
1040                         }
1041                 }
1042                 
1043                 return map;
1044                 
1045         }
1046
1047         public static Map<String, Variable> collectSubliteralProperties(ReadGraph graph, StandardGraphPropertyVariable variable, Map<String, Variable> map) throws DatabaseException {
1048
1049                 Resource predicate = variable.property.predicate;
1050                 if(predicate == null) return map;
1051                 
1052                 PropertyInfo info = getPropertyInfo(graph, predicate);
1053                 if(info.subliteralPredicates.isEmpty()) return map;
1054                 
1055                 map = ensureVariableMap(map, info.subliteralPredicates.size());
1056                 
1057                 for(Map.Entry<String, Pair<Resource, ChildReference>> entry : info.subliteralPredicates.entrySet()) {
1058                         String key = entry.getKey();
1059                         Pair<Resource, ChildReference> p = entry.getValue();
1060                         if(map == null) map = new THashMap<String,Variable>();
1061                         map.put(key, new SubliteralPropertyVariable(graph, variable, p.first, p.second));
1062                 }
1063         
1064         return map;
1065                 
1066         }
1067
1068         public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, String classification, Map<String, Variable> map) throws DatabaseException {
1069
1070                 if(graph.isImmutable(context)) {
1071
1072                         Map<String,PropertyInfo> properties = graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance());
1073                         for(PropertyInfo info : properties.values()) {
1074
1075                                 if(info.classifications.contains(classification) && info.builder != null) {
1076                                         String name = info.name;
1077                                         Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1078                                         if(map == null) map = new THashMap<String,Variable>();
1079                                         map.put(name, v);
1080                                 }
1081
1082                         }
1083
1084                 } else {
1085                                 
1086                         Collection<Resource> predicates = graph.getPredicates(context);
1087                                         
1088                         if(predicates.isEmpty()) return map;
1089                         
1090                         map = ensureVariableMap(map, predicates.size());
1091                 
1092                         for(Resource predicate : predicates) {
1093                                 
1094                                 PropertyInfo info = graph.isImmutable(predicate) ?
1095                                                 graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
1096                                                         graph.syncRequest(new PropertyInfoRequest(predicate));
1097                                                 
1098                                 if(!info.isHasProperty) continue;
1099         
1100                                 if(info.classifications.contains(classification) && info.builder != null) {
1101                                         String name = info.name;
1102                                         Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1103                                         if(map == null) map = new THashMap<String,Variable>();
1104                                         map.put(name, v);
1105                                 }
1106                                 
1107                         }
1108                         
1109                 }
1110                 
1111                 return map;
1112                 
1113         }       
1114         
1115     @SCLValue(type = "ReadGraph -> Resource -> a -> String")
1116     public static String entityLabel(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1117         if(context instanceof Resource) {
1118                 return NameUtils.getSafeLabel(graph, ((Resource)context));      
1119         } else if (context instanceof Variable) {
1120                 Variable parent = ((Variable)context).getParent(graph);
1121                 Resource represents = parent.getRepresents(graph);
1122                 return NameUtils.getSafeLabel(graph, represents);
1123         } else {
1124                 throw new DatabaseException("Unknown context " + context);
1125         }
1126     }
1127
1128     @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1129     public static Object listResources(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1130         return ListUtils.toList(graph, resource);
1131     }
1132
1133     @SCLValue(type = "ReadGraph -> Resource -> Variable -> [String]")
1134     public static List<String> standardClassifications(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1135         ArrayList<String> result = new ArrayList<String>();
1136         Resource predicate = context.getParent(graph).getPossiblePredicateResource(graph);
1137         if(predicate != null) {
1138                 for(Resource type : graph.getTypes(predicate)) {
1139                         String uri = graph.getPossibleURI(type);
1140                         if(uri != null) result.add(uri);
1141                 }
1142         }
1143         return result;
1144     }
1145
1146     @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1147     public static Boolean standardValidValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1148         return Boolean.TRUE;
1149     }
1150
1151     @SCLValue(type = "ReadGraph -> Resource -> a -> StringInputValidator")
1152     public static StringInputValidator standardValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1153         return StringInputValidator.PASS;
1154     }
1155
1156     @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1157     public static Boolean standardRequiredValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1158         return Boolean.FALSE;
1159     }
1160
1161     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Boolean")
1162     public static Boolean standardDefaultValue(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1163         Variable property = context.getParent(graph);
1164         if(property instanceof StandardGraphPropertyVariable) {
1165                 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)property;
1166                 if (variable.parentResource != null) {
1167                         Resource predicate = variable.getPossiblePredicateResource(graph);
1168                         if (predicate != null) {
1169                                         Statement stm = graph.getPossibleStatement(variable.parentResource, predicate);
1170                                         return stm != null && stm.isAsserted(variable.parentResource);
1171                         }
1172                         }
1173         }
1174         return Boolean.FALSE;
1175     }
1176
1177     @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1178     public static Boolean standardReadOnlyValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1179         return Boolean.FALSE;
1180     }
1181
1182     @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1183     public static Object resourceAsValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1184         return resource;
1185     }
1186     
1187     @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1188     public static Object functionApplication(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1189         return Functions.exec(graph, resource, graph, resource, context);
1190     }
1191
1192     @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1193     public static Object computeExpression(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1194         if(context instanceof Variable) {
1195             return CompileValueRequest.compileAndEvaluate(graph, (Variable)context);
1196         } if (context instanceof Resource) {
1197             return CompileResourceValueRequest.compileAndEvaluate(graph, (Resource)converter);
1198         } else {
1199                 throw new IllegalStateException("Unknown context " + context);
1200         }
1201     }
1202
1203     @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1204     public static Object composedPropertyValue(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1205         if(context instanceof Variable) {
1206                 return new StandardComposedProperty();
1207         } if (context instanceof Resource) {
1208                 return new StandardComposedProperty();
1209         } else {
1210                 throw new IllegalStateException("Unknown context " + context);
1211         }
1212     }
1213     
1214     @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1215     public static Object numberInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1216         
1217         class Validator extends FunctionImpl1<String, String> {
1218
1219             private final Datatype datatype;
1220             
1221             public Validator(Datatype datatype) {
1222                 this.datatype = datatype;
1223             }
1224             
1225             @Override
1226             public String apply(String input) {
1227                 
1228                 if(datatype == null) return null;
1229                 
1230                 try {
1231
1232                     if(datatype instanceof NumberType) {
1233                         
1234                         Number number = (Number)PrimitiveValueParser.parse(input, datatype);
1235                         NumberType nt = (NumberType)datatype;
1236                         Range r = nt.getRange();
1237                         if(r != null) {
1238                             if(!r.contains(number)) return "Value is out of valid range";
1239                         }
1240                     }
1241                     return null;
1242                     
1243                 } catch (NumberFormatException e) {
1244                     return "Not a valid floating-point number";
1245                 } catch (IllegalArgumentException e) {
1246                     return "Not a valid floating-point number";
1247                 }
1248                 
1249             }
1250             
1251         }
1252
1253         if(context instanceof Variable) {
1254             
1255             Variable variable = (Variable)context;
1256             Variable property = variable.getParent(graph);
1257             Datatype datatype = property.getPossibleDatatype(graph);
1258             return new Validator(datatype);
1259             
1260         } else if (context instanceof Resource) {
1261
1262             Layer0 L0 = Layer0.getInstance(graph);
1263             Resource literal = (Resource)context;
1264             Datatype datatype = graph.getRelatedValue(literal, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
1265             return new Validator(datatype);
1266             
1267         } else {
1268             
1269             return new Validator(null);
1270             
1271         }
1272         
1273     }
1274     
1275     @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1276     public static Object booleanInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1277         
1278         return new FunctionImpl1<String, String>() {
1279
1280             @Override
1281             public String apply(String input) {
1282                 
1283                 String lower = input.toLowerCase();
1284                 if("true".equals(lower) || "false".equals(lower)) return null;
1285
1286                 return "Not a valid boolean: " + input;
1287                 
1288             }
1289             
1290         };
1291         
1292     }
1293
1294     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Resource")
1295     public static Resource hasStandardResource(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1296         Variable parent = context.getParent(graph);
1297         if(parent instanceof StandardGraphChildVariable) {
1298                 StandardGraphChildVariable variable = (StandardGraphChildVariable)parent;
1299                 return variable.resource;
1300         }
1301         return null;
1302     }
1303
1304
1305     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1306         public static Object valueWithoutBinding(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1307
1308         StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1309                 
1310                 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1311                         Layer0 L0 = Layer0.getInstance(graph);
1312                         return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel);
1313                 }
1314
1315                 if (variable.parentResource == null)
1316                         throw new InvalidVariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").");
1317
1318                 try {
1319                         return graph.getRelatedValue2(variable.parentResource, variable.getPredicateResource(graph), variable);
1320                 } catch (NoSingleResultException e) {
1321                         throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1322                 } catch (DoesNotContainValueException e) {
1323                         throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1324                 }
1325                 
1326         }
1327
1328     @SCLValue(type = "ReadGraph -> Variable -> Binding -> a")
1329         public static Object valueWithBinding(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
1330
1331         StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1332                 
1333                 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1334                         Layer0 L0 = Layer0.getInstance(graph);
1335                         return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
1336                 }
1337
1338                 if (variable.parentResource == null)
1339                         throw new MissingVariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").", context.getPossibleRepresents(graph));
1340                 
1341
1342                 try {
1343                         return graph.getRelatedValue2(variable.parentResource, variable.getPredicateResource(graph), variable);
1344                 } catch (NoSingleResultException e) {
1345                         throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1346                 } catch (DoesNotContainValueException e) {
1347                         throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1348                 }
1349                 
1350         }
1351
1352     @SCLValue(type = "WriteGraph -> Variable -> a -> Binding -> b")
1353         public static Object valueSetterWithBinding(WriteGraph graph, Variable variable, Object value, Binding binding) throws DatabaseException {
1354                 
1355                 Function4<WriteGraph, Variable, Object, Object, String> modifier = variable.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
1356                 if(modifier == null) modifier = VariableUtils.defaultInputModifier; 
1357                 modifier.apply(graph, variable, value, binding);
1358                 return null;
1359                 
1360         }
1361     
1362     static class L0Issue extends StandardIssue {
1363         
1364         private final String description;
1365         
1366         public L0Issue(String description, Resource type, Resource ... contexts) {
1367             super(type, contexts);
1368             this.description = description;
1369         }
1370
1371         @Override
1372         public Resource write(WriteGraph graph, Resource source) throws DatabaseException {
1373             Layer0 L0 = Layer0.getInstance(graph);
1374             IssueResource IR = IssueResource.getInstance(graph);
1375             Resource issue = super.write(graph, source);
1376             graph.claim(issue, IR.Issue_HasSeverity, IR.Severity_Fatal);
1377             graph.addLiteral(issue, L0.HasDescription, L0.HasDescription_Inverse, description, Bindings.STRING);
1378             return issue;
1379         }
1380         
1381     }
1382     
1383         private static List<Issue> reportInconsistency(ReadGraph graph, Resource subject, String description, List<Issue> issues) throws DatabaseException {
1384             if(issues == null) issues = new ArrayList<Issue>();
1385                 System.err.println("Change set validation reports the following issue: " + NameUtils.getSafeName(graph, subject, true) + ": " + description);
1386                 IssueResource IR = IssueResource.getInstance(graph);
1387                 issues.add(new L0Issue(description, IR.Issue, subject));
1388                 return issues;
1389         }
1390     
1391     @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1392     public static List<Issue> relationValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1393
1394         Layer0 L0 = Layer0.getInstance(graph);
1395
1396         List<Issue> issues = null;
1397         
1398         for(Statement stm : graph.getStatements(resource, L0.IsWeaklyRelatedTo)) {
1399                 Resource predicate = stm.getPredicate();
1400                 Resource object = stm.getObject();
1401                 if(!isRelation(graph, L0, predicate)) {
1402                         issues = reportInconsistency(graph, resource, "The predicate of a statement must be a relation: " + NameUtils.toString(graph, stm), issues);
1403                 }
1404                 if(graph.isInstanceOf(predicate, L0.FunctionalRelation)) {
1405                         if(graph.getObjects(resource, predicate).size() > 1)
1406                                 issues = reportInconsistency(graph, resource, 
1407                                                 "Relation " +
1408                                                                 NameUtils.getSafeName(graph, predicate)
1409                                                                 + " is functional.", issues);
1410                 }
1411                 {
1412                         Collection<Resource> domain = graph.getObjects(predicate, L0.HasDomain);
1413                         if (!isInstanceOfAny(graph, resource, domain, true)) {
1414                                 StringBuilder sb = new StringBuilder()
1415                                 .append("The domain of ")
1416                                 .append(NameUtils.getSafeName(graph, predicate))
1417                                 .append(" relation is ");
1418                                 orString(graph, sb, domain).append(".");
1419                                 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1420                         }
1421                 }
1422                 {
1423                         Collection<Resource> range = graph.getObjects(predicate, L0.HasRange);
1424                         if (!isInstanceOfAny(graph, object, range, true) && !graph.isInstanceOf(object, L0.SCLValue)) {
1425                                 StringBuilder sb = new StringBuilder()
1426                                 .append("The range of ")
1427                                 .append(NameUtils.getSafeName(graph, predicate))
1428                                 .append(" relation is ");
1429                                 orString(graph, sb, range).append(" but current object is ")
1430                                 .append(NameUtils.getSafeName(graph, object)).append(".");
1431                                 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1432                         }
1433                 }               
1434         }
1435                 
1436                 return issues != null ? issues : Collections.<Issue>emptyList();
1437
1438     }
1439
1440     @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1441     public static List<Issue> propertyValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1442
1443         List<Issue> issues = null;
1444
1445         Layer0 L0 = Layer0.getInstance(graph);
1446         for(Statement stm : graph.getStatements(resource, L0.HasProperty)) {
1447                 Resource subject = stm.getSubject();
1448                 Resource predicate = stm.getPredicate();
1449                 String error = L0Validations.checkValueType(graph, subject, predicate);
1450                 if(error != null) issues = reportInconsistency(graph, subject, error, issues);
1451         }
1452                 
1453         return issues != null ? issues : Collections.<Issue>emptyList();
1454
1455     }
1456     
1457     
1458     @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1459     public static List<Issue> valueValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1460
1461         List<Issue> issues = null;
1462
1463         Layer0 L0 = Layer0.getInstance(graph);
1464         if(graph.hasValue(resource)) {
1465                 if(!graph.isInstanceOf(resource, L0.Literal)) {
1466                         issues = reportInconsistency(graph, resource, 
1467                                         "Resource has a value but it is not a literal.", issues);
1468                 }
1469                 else {
1470                         // TODO check that the value is valid for the data type
1471                 }
1472         }
1473         else {
1474                 if(graph.isInstanceOf(resource, L0.Literal)) {
1475                         issues = reportInconsistency(graph, resource, 
1476                                         "Resource is a literal but it does not have a value.", issues);
1477                 }
1478         }
1479         
1480         return issues != null ? issues : Collections.<Issue>emptyList();
1481         
1482     }
1483
1484     
1485     @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1486     public static List<Issue> uriValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1487         
1488         List<Issue> issues = null;
1489
1490         Layer0 L0 = Layer0.getInstance(graph);
1491         Resource parent = graph.getPossibleObject(resource, L0.PartOf);
1492         if(parent != null) {
1493             String parentURI = graph.syncRequest(new PossibleURI(parent));
1494             if(parentURI != null) {
1495                         String name = graph.getPossibleRelatedValue(resource, L0.HasName);
1496                         if(name == null) {
1497                                 issues = reportInconsistency(graph, resource, "Resource has a parent with URI but has no valid HasName.", issues);
1498                         }
1499             }
1500         }
1501
1502         return issues != null ? issues : Collections.<Issue>emptyList();
1503         
1504     }
1505     
1506     private static Resource getPossibleNearestClusterSet(ReadGraph graph, Resource base, Resource resource) throws DatabaseException {
1507
1508         ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1509         if(cs.isClusterSet(resource) && !base.equals(resource)) return resource;
1510         
1511         Resource nearest = NearestOwnerFinder.getNearestOwner(graph, resource);
1512         if(nearest == null) return null;
1513         
1514         return getPossibleNearestClusterSet(graph, base, nearest);
1515
1516     }
1517
1518     private static boolean quirks(ReadGraph graph, Resource resource) throws DatabaseException {
1519
1520         if(!resource.isPersistent()) return true;
1521         if(graph.isImmutable(resource)) return true;
1522         if(resource.getResourceId() < 0x2000) return true;
1523
1524         return false;
1525         
1526     }
1527     
1528     @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1529     public static List<Issue> clusterValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1530
1531         if(!Development.DEVELOPMENT) return Collections.<Issue>emptyList();
1532         
1533         if(quirks(graph, resource)) return Collections.<Issue>emptyList();
1534         
1535         List<Issue> issues = null;
1536
1537         ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1538         Resource set = cs.getClusterSetOfCluster(resource);
1539         
1540         if(set == null) return reportInconsistency(graph, resource, "Resource cluster is not part of any cluster set", issues);
1541         
1542         Resource nearestSet = getPossibleNearestClusterSet(graph, resource, resource);
1543         if(nearestSet == null) {
1544                 // This means that there is no owner since RootLibrary is a cluster set
1545                 return Collections.<Issue>emptyList();
1546         }
1547         
1548         if(!set.equals(nearestSet)) return reportInconsistency(graph, resource, "The cluster set of a resource is not the nearest owner set", issues);
1549
1550         return Collections.<Issue>emptyList();
1551         
1552     }
1553
1554     private static boolean isInstanceOfAny(ReadGraph graph, Resource r, Collection<Resource> types, boolean ifEmpty) throws DatabaseException {
1555                 if (types.isEmpty())
1556                         return ifEmpty;
1557                 for (Resource type : types) {
1558                         if (graph.isInstanceOf(r, type)) {
1559                                 return true;
1560                         }
1561                 }
1562                 return false;
1563         }
1564
1565         private static StringBuilder orString(ReadGraph graph, StringBuilder sb, Collection<Resource> rs) throws DatabaseException {
1566                 sb.append("(");
1567                 boolean first = true;
1568                 for (Resource r : rs) {
1569                         if (!first)
1570                                 sb.append(" | ");
1571                         first = false;
1572                         sb.append(NameUtils.getSafeName(graph, r));
1573                 }
1574                 sb.append(")");
1575                 return sb;
1576         }
1577
1578     public static boolean isRelation(ReadGraph g, Layer0 l0, Resource relation) throws DatabaseException {
1579                 return g.hasStatement(relation, l0.SubrelationOf) || relation == l0.IsWeaklyRelatedTo;
1580         }
1581         
1582         public static boolean isType(ReadGraph g, Layer0 l0, Resource type) throws DatabaseException {
1583                 return g.hasStatement(type, l0.Inherits) || type == l0.Entity;
1584         }
1585         
1586     public static Variable buildChildVariable(ReadGraph graph, Variable context, Resource graphChild, Object nodeChild) throws DatabaseException {
1587         VariableBuilder builder = graph.adapt(graphChild, VariableBuilder.class);
1588         return builder.buildChild(graph, context, build(((AbstractVariable)context).node, nodeChild), graphChild);
1589         }
1590
1591         private static Variable buildPropertyVariable(ReadGraph graph, Variable variable, Resource parentResource, PropertyInfo graphProperty, Object propertyNode) throws DatabaseException {
1592                 VariableNode<?> node = variable instanceof AbstractVariable ? build(((AbstractVariable)variable).node, propertyNode) : null;
1593                 return graphProperty.builder.buildProperty(graph, variable, node, parentResource, graphProperty.predicate);
1594         }
1595         
1596         static StandardGraphChildVariable createStandardGraphChildVariable(
1597                         AbstractVariable parent, Object child) {
1598                 return new StandardGraphChildVariable(parent, build(parent.node, child), null);
1599         }
1600
1601         private static StandardGraphPropertyVariable createStandardGraphPropertyVariable(
1602                         ReadGraph graph, AbstractVariable variable, Object nodeProperty) throws DatabaseException {
1603         Resource propertyResource = getPossiblePropertyResource(graph, variable, nodeProperty);
1604         return new StandardGraphPropertyVariable(graph, variable, build(variable.node, nodeProperty), null, propertyResource);
1605         }
1606         
1607         static Map<String, Variable> ensureVariableMap(
1608                         Map<String, Variable> map, int size) {
1609                 if(map == null) map = new THashMap<String,Variable>(size);
1610                 return map;
1611         }
1612
1613         private static PropertyInfo getPropertyInfo(ReadGraph graph, Resource predicate) throws DatabaseException {
1614                 return graph.syncRequest(new PropertyInfoRequest(predicate));
1615         }
1616
1617         @SuppressWarnings("unchecked")
1618         static String getNodeName(AbstractVariable parent, Object child) {
1619                 return parent.node.support.manager.getName(child);
1620         }
1621
1622         @SuppressWarnings("unchecked")
1623         private static Object getNodeValue(final AbstractVariable variable, final Binding binding) throws NodeManagerException, BindingException {
1624                 return variable.node.support.manager.getValue(variable.node.node, binding);
1625         }
1626
1627         @SuppressWarnings("unchecked")
1628         private static void setNodeValue(final AbstractVariable variable, final Object value, final Binding binding) throws NodeManagerException, BindingException {
1629                 variable.node.support.manager.setValue(variable.node.node, value, binding);
1630         }
1631         
1632         @SuppressWarnings("unchecked")
1633         private static String getPossiblePropertyURI(AbstractVariable parent, Object node) {
1634                 return parent.node.support.manager.getPropertyURI(parent.node.node, node);
1635         }
1636     
1637
1638     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1639     public static Object defaultInstantiateUnder(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1640         return new FunctionImpl2<Resource, Resource, Resource>() {
1641             public Resource apply(Resource container, Resource type) {
1642                 try {
1643                     WriteGraph graph = (WriteGraph)SCLContext.getCurrent().get("graph");
1644
1645                     Layer0 L0 = Layer0.getInstance(graph);
1646                     CommonDBUtils.selectClusterSet(graph, container);
1647                     Resource result = graph.newResource();
1648                     String name = NameUtils.findFreshInstanceName(graph, type, container);
1649                     graph.claim(result, L0.InstanceOf, type);
1650                     graph.addLiteral(result, L0.HasName, L0.NameOf, name, Bindings.STRING);
1651                     graph.claim(container, L0.ConsistsOf, L0.PartOf, result);
1652
1653                     return result;
1654                 } catch (DatabaseException e) {
1655                     throw new RuntimeDatabaseException(e);
1656                 }
1657             }
1658         };
1659     }
1660
1661 }