1 package org.simantics.db.layer0.function;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.HashMap;
10 import java.util.concurrent.atomic.AtomicReference;
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;
96 import gnu.trove.map.hash.THashMap;
97 import gnu.trove.set.hash.THashSet;
101 public static Object standardGetValue1(ReadGraph graph, Variable context) throws DatabaseException {
103 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
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();
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);
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>";
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());
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);
141 for (Pair<PropertyInfo, Resource> assertion : assertions.values()) {
142 if (assertion.first.predicate.equals(variable.property.predicate)) {
143 return graph.getValue2(assertion.second, variable);
150 return graph.getValue2(variable.getRepresents(graph), variable);
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);
162 public static Object standardGetValue2(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
163 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
166 if(variable.node != null) {
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);
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);
186 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
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());
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);
203 for (Pair<PropertyInfo, Resource> assertion : assertions.values()) {
204 if (assertion.first.predicate.equals(variable.property.predicate)) {
205 return graph.getValue2(assertion.second, variable, binding);
212 return graph.getValue2(variable.getRepresents(graph), context, binding);
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);
224 public static void standardSetValue2(WriteGraph graph, Variable context, final Object value) throws DatabaseException {
226 if(context instanceof StandardGraphPropertyVariable) {
228 final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
231 if(variable.node != null) {
233 final Binding binding = Layer0Utils.getDefaultBinding(graph, variable);
235 final AtomicReference<Object> oldValueRef = new AtomicReference<Object>();
237 variable.node.support.manager.getRealm().syncExec(new Runnable() {
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);
250 } catch(RuntimeException e) {
251 if(e.getCause() instanceof NodeManagerException || e.getCause() instanceof BindingException)
252 throw new DatabaseException(e.getCause());
255 } catch (InterruptedException e) {
256 throw new DatabaseException(e);
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);
268 Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
269 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
271 modifier.apply(graph, context, value, Bindings.getBinding(value.getClass()));
272 } catch (BindingConstructionException e) {
273 throw new org.simantics.db.exception.BindingException("",e);
278 public static void standardSetValue3(final WriteGraph graph, Variable context, final Object value, final Binding binding) throws DatabaseException {
281 if(context instanceof StandardGraphPropertyVariable) {
283 final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
286 if(variable.node != null) {
290 variable.node.support.manager.getRealm().syncExec(new Runnable() {
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);
309 } catch (InterruptedException e) {
310 throw new DatabaseException(e);
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);
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();
330 Variant value = context.getVariantValue(graph);
331 if (value.getBinding() == null)
332 throw new DatabaseException("No value binding for " + context.getURI(graph));
334 return value.getBinding().type();
337 @SuppressWarnings("rawtypes")
338 private static class DatatypeGetter implements VariableNodeReadRunnable {
339 final VariableNode node;
343 public DatatypeGetter(VariableNode node) {
347 @SuppressWarnings("unchecked")
351 type = node.support.manager.getDatatype(node.node);
352 } catch (NodeManagerException e) {
357 public String toString() {
358 return "DatatypeGetter(" + node.node + ")";
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) {
367 DatatypeGetter request = new DatatypeGetter(variable.node);
369 variable.node.support.manager.getRealm().syncExec(request);
371 if (request.exception != null)
372 throw new DatabaseException(request.exception);
375 } catch (InterruptedException e) {
380 return getDatatypeFromValue(graph, context);
383 // @SCLValue(type = "ValueAccessor")
384 // public static ValueAccessor standardValueAccessor = new ValueAccessor() {
387 // public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
388 // return standardGetValue(graph, (StandardGraphPropertyVariable)context);
392 // public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
393 // return standardGetValue(graph, context, binding);
397 // public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
398 // standardSetValue(graph, context, value);
402 // public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
403 // standardSetValue(graph, context, value, binding);
407 // public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
408 // return standardGetDatatype(graph, context);
413 @SCLValue(type = "ValueAccessor")
414 public static ValueAccessor standardValueAccessor = new ValueAccessor() {
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);
421 return standardGetValue1(graph, context);
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);
429 return standardGetValue2(graph, context, binding);
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);
437 standardSetValue2(graph, context, value);
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);
445 standardSetValue3(graph, context, value, binding);
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);
454 return standardGetDatatype(graph, context);
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);
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);
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);
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) {
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());
497 Map<String, Pair<PropertyInfo, Resource>> pm = graph.syncRequest(
498 new UnescapedAssertedPropertyMapOfResource(type),
499 TransientCacheAsyncListener.instance());
500 Pair<PropertyInfo, Resource> pi = pm.get(name);
502 return new StandardAssertedGraphPropertyVariable(graph, context, null, type, pi.first.predicate, pi.second);
506 } catch(NodeManagerException e) {
507 throw new DatabaseException(e);
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);
518 public static Map<String, Variable> getStandardChildDomainPropertyVariables(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
520 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
522 Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
523 if(!nodeProperties.isEmpty()) {
525 // Get variables for properties read from the graph
526 Map<String,PropertyInfo> graphProperties = collectPropertyInfosFromContext(graph, variable, variable.resource);
528 Set<String> used = new THashSet<String>(nodeProperties.size());
530 map = ensureVariableMap(map, graphProperties.size() + nodeProperties.size());
532 // Process NodeManager property nodes
533 for(Object nodeProperty : nodeProperties) {
534 String name = getNodeName(variable, nodeProperty);
537 PropertyInfo graphProperty = graphProperties.get(name);
538 if(graphProperty != null && graphProperty.builder != null) {
539 if (classification != null && !graphProperty.hasClassification(classification)) continue;
541 // Combine with identically named graph property
542 map.put(name, buildPropertyVariable(graph, variable, variable.resource, graphProperty, nodeProperty));
546 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
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));
562 if(variable.resource == null) return map;
564 // Only graph properties
565 Collection<Resource> predicates = graph.getPredicates(variable.resource);
566 if(predicates.isEmpty()) return map;
568 map = ensureVariableMap(map, predicates.size());
570 // Process graph properties
571 for(Resource predicate : predicates) {
573 PropertyInfo info = //graph.isImmutable(predicate) ?
574 graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance());// :
575 //graph.syncRequest(new PropertyInfoRequest(predicate));
577 if(!info.isHasProperty) continue;
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));
592 @SCLValue(type = "VariableMap")
593 public static VariableMap standardChildDomainProperties = new VariableMapImpl() {
596 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
597 return getStandardChildDomainPropertyVariable(graph, context, name);
601 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
602 return getStandardChildDomainPropertyVariables(graph, context, map);
607 @SCLValue(type = "VariableMap")
608 public static VariableMap methodsPropertyDomainProperties = new VariableMapImpl() {
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)
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);
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));
648 public static Variable getStandardPropertyDomainPropertyVariableFromValue(ReadGraph graph, Variable context, String name) throws DatabaseException {
650 if(context instanceof StandardGraphPropertyVariable) {
651 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
652 Resource literal = variable.getPossibleRepresents(graph);
653 Object propertyNode = getPossibleNodeProperty(graph, variable, name, false);
655 if(literal != null) {
656 Variable result = getPossiblePropertyFromContext(graph, variable, literal, name, propertyNode);
657 if(result != null) return result;
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;
665 // Get possible property from NodeManager
666 if (propertyNode != null)
667 return createStandardGraphPropertyVariable(graph, variable, propertyNode);
669 } else if (context instanceof StandardGraphChildVariable) {
670 return standardChildDomainProperties.getVariable(graph, context, name);
672 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
677 public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
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);
688 // Get properties from VariableNode
689 map = getStandardNodePropertyVariables(graph, context, map);
691 } else if (context instanceof StandardGraphChildVariable) {
692 return standardChildDomainProperties.getVariables(graph, context, map);
694 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
699 public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
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);
709 // Get properties from VariableNode
710 map = getStandardNodePropertyVariables(graph, context, map);
712 } else if (context instanceof StandardGraphChildVariable) {
713 return standardChildDomainProperties.getVariables(graph, context, map);
715 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
720 @SCLValue(type = "VariableMap")
721 public static VariableMap standardPropertyDomainProperties = new VariableMapImpl() {
723 VariableMap getValueVariableMap(ReadGraph graph, Variable context) throws DatabaseException {
724 Resource represents = context.getPossibleRepresents(graph);
725 if(represents == null) return null;
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);
731 if(map == standardPropertyDomainProperties) return null;
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);
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);
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);
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);
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));
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);
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();
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);
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();
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);
815 public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
816 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
820 public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, Resource graphChild, String name) throws DatabaseException {
821 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, graphChild, name);
825 public static Map<String, Variable> getStandardChildDomainChildVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
826 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
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);
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
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;
846 Collection<Object> nodeChildren = getPossibleNodeChildren(graph, variable);
847 if (nodeChildren.isEmpty()) return map;
849 map = ensureVariableMap(map, nodeChildren.size());
851 for(Object nodeChild : nodeChildren) {
852 String name = getNodeName(variable, nodeChild);
853 if (!map.containsKey(name))
854 map.put(name, createStandardGraphChildVariable(variable, nodeChild));
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
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;
872 Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
873 if (nodeProperties.isEmpty()) return map;
875 map = ensureVariableMap(map, nodeProperties.size());
877 for(Object nodeProperty : nodeProperties) {
878 String name = getNodeName(variable, nodeProperty);
879 if (!map.containsKey(name)) {
880 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
887 @SCLValue(type = "VariableMap")
888 public static VariableMap standardChildDomainChildren = new VariableMapImpl() {
891 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
892 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
896 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
897 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
902 @SCLValue(type = "VariableMap")
903 public static VariableMap standardPropertyDomainChildren = new VariableMapImpl() {
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
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;
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);
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);
933 return new SubliteralPropertyVariableDeprecated(variable, ref);
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);
942 return standardChildDomainChildren.getVariable(graph, context, name);
943 } else if (context instanceof StandardGraphChildVariable) {
944 return standardChildDomainChildren.getVariable(graph, context, name);
946 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
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);
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);
963 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
969 protected static ChildReference getPossibleIndexReference(String name) {
970 if (name.startsWith("i-")) {
972 int index = Integer.parseInt(name.substring(2));
973 return new IndexReference(index);
974 } catch (NumberFormatException e) {}
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));
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));
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);
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);
1005 public static Variable getPossibleSubliteralPropertyFromContext(ReadGraph graph, StandardGraphPropertyVariable variable, String name) throws DatabaseException {
1007 Resource predicate = variable.property.predicate;
1008 if(predicate == null) return null;
1010 PropertyInfo info = getPropertyInfo(graph, predicate);
1011 Pair<Resource, ChildReference> p = info.subliteralPredicates.get(name);
1012 if(p == null) return null;
1014 return new SubliteralPropertyVariable(graph, variable, p.first, p.second);
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));
1025 public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, Map<String, Variable> map) throws DatabaseException {
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));
1031 if(properties.isEmpty()) return map;
1033 map = ensureVariableMap(map, properties.size());
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);
1047 public static Map<String, Variable> collectSubliteralProperties(ReadGraph graph, StandardGraphPropertyVariable variable, Map<String, Variable> map) throws DatabaseException {
1049 Resource predicate = variable.property.predicate;
1050 if(predicate == null) return map;
1052 PropertyInfo info = getPropertyInfo(graph, predicate);
1053 if(info.subliteralPredicates.isEmpty()) return map;
1055 map = ensureVariableMap(map, info.subliteralPredicates.size());
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));
1068 public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, String classification, Map<String, Variable> map) throws DatabaseException {
1070 if(graph.isImmutable(context)) {
1072 Map<String,PropertyInfo> properties = graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance());
1073 for(PropertyInfo info : properties.values()) {
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>();
1086 Collection<Resource> predicates = graph.getPredicates(context);
1088 if(predicates.isEmpty()) return map;
1090 map = ensureVariableMap(map, predicates.size());
1092 for(Resource predicate : predicates) {
1094 PropertyInfo info = graph.isImmutable(predicate) ?
1095 graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
1096 graph.syncRequest(new PropertyInfoRequest(predicate));
1098 if(!info.isHasProperty) continue;
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>();
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);
1124 throw new DatabaseException("Unknown context " + context);
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);
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);
1146 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1147 public static Boolean standardValidValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1148 return Boolean.TRUE;
1151 @SCLValue(type = "ReadGraph -> Resource -> a -> StringInputValidator")
1152 public static StringInputValidator standardValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1153 return StringInputValidator.PASS;
1156 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1157 public static Boolean standardRequiredValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1158 return Boolean.FALSE;
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 Statement stm = graph.getPossibleStatement(variable.parentResource, variable.property.predicate);
1168 return stm != null && stm.isAsserted(variable.parentResource);
1171 return Boolean.FALSE;
1174 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1175 public static Boolean standardReadOnlyValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1176 return Boolean.FALSE;
1179 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1180 public static Object resourceAsValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1184 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1185 public static Object functionApplication(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1186 return Functions.exec(graph, resource, graph, resource, context);
1189 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1190 public static Object computeExpression(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1191 if(context instanceof Variable) {
1192 return CompileValueRequest.compileAndEvaluate(graph, (Variable)context);
1193 } if (context instanceof Resource) {
1194 return CompileResourceValueRequest.compileAndEvaluate(graph, (Resource)converter);
1196 throw new IllegalStateException("Unknown context " + context);
1200 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1201 public static Object composedPropertyValue(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1202 if(context instanceof Variable) {
1203 return new StandardComposedProperty();
1204 } if (context instanceof Resource) {
1205 return new StandardComposedProperty();
1207 throw new IllegalStateException("Unknown context " + context);
1211 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1212 public static Object numberInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1214 class Validator extends FunctionImpl1<String, String> {
1216 private final Datatype datatype;
1218 public Validator(Datatype datatype) {
1219 this.datatype = datatype;
1223 public String apply(String input) {
1225 if(datatype == null) return null;
1229 if(datatype instanceof NumberType) {
1231 Number number = (Number)PrimitiveValueParser.parse(input, datatype);
1232 NumberType nt = (NumberType)datatype;
1233 Range r = nt.getRange();
1235 if(!r.contains(number)) return "Value is out of valid range";
1240 } catch (NumberFormatException e) {
1241 return "Not a valid floating-point number";
1242 } catch (IllegalArgumentException e) {
1243 return "Not a valid floating-point number";
1250 if(context instanceof Variable) {
1252 Variable variable = (Variable)context;
1253 Variable property = variable.getParent(graph);
1254 Datatype datatype = property.getPossibleDatatype(graph);
1255 return new Validator(datatype);
1257 } else if (context instanceof Resource) {
1259 Layer0 L0 = Layer0.getInstance(graph);
1260 Resource literal = (Resource)context;
1261 Datatype datatype = graph.getRelatedValue(literal, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
1262 return new Validator(datatype);
1266 return new Validator(null);
1272 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1273 public static Object booleanInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1275 return new FunctionImpl1<String, String>() {
1278 public String apply(String input) {
1280 String lower = input.toLowerCase();
1281 if("true".equals(lower) || "false".equals(lower)) return null;
1283 return "Not a valid boolean: " + input;
1291 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Resource")
1292 public static Resource hasStandardResource(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1293 Variable parent = context.getParent(graph);
1294 if(parent instanceof StandardGraphChildVariable) {
1295 StandardGraphChildVariable variable = (StandardGraphChildVariable)parent;
1296 return variable.resource;
1302 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1303 public static Object valueWithoutBinding(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1305 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1307 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1308 Layer0 L0 = Layer0.getInstance(graph);
1309 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel);
1312 if (variable.parentResource == null)
1313 throw new InvalidVariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").");
1316 return graph.getRelatedValue2(variable.parentResource, variable.property.predicate, variable);
1317 } catch (NoSingleResultException e) {
1318 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1319 } catch (DoesNotContainValueException e) {
1320 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1325 @SCLValue(type = "ReadGraph -> Variable -> Binding -> a")
1326 public static Object valueWithBinding(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
1328 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1330 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1331 Layer0 L0 = Layer0.getInstance(graph);
1332 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
1335 if (variable.parentResource == null)
1336 throw new MissingVariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").", context.getPossibleRepresents(graph));
1339 return graph.getRelatedValue2(variable.parentResource, variable.property.predicate, variable);
1340 } catch (NoSingleResultException e) {
1341 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1342 } catch (DoesNotContainValueException e) {
1343 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1348 @SCLValue(type = "WriteGraph -> Variable -> a -> Binding -> b")
1349 public static Object valueSetterWithBinding(WriteGraph graph, Variable variable, Object value, Binding binding) throws DatabaseException {
1351 Function4<WriteGraph, Variable, Object, Object, String> modifier = variable.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
1352 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
1353 modifier.apply(graph, variable, value, binding);
1358 static class L0Issue extends StandardIssue {
1360 private final String description;
1362 public L0Issue(String description, Resource type, Resource ... contexts) {
1363 super(type, contexts);
1364 this.description = description;
1368 public Resource write(WriteGraph graph, Resource source) throws DatabaseException {
1369 Layer0 L0 = Layer0.getInstance(graph);
1370 IssueResource IR = IssueResource.getInstance(graph);
1371 Resource issue = super.write(graph, source);
1372 graph.claim(issue, IR.Issue_HasSeverity, IR.Severity_Fatal);
1373 graph.addLiteral(issue, L0.HasDescription, L0.HasDescription_Inverse, description, Bindings.STRING);
1379 private static List<Issue> reportInconsistency(ReadGraph graph, Resource subject, String description, List<Issue> issues) throws DatabaseException {
1380 if(issues == null) issues = new ArrayList<Issue>();
1381 System.err.println("Change set validation reports the following issue: " + NameUtils.getSafeName(graph, subject, true) + ": " + description);
1382 IssueResource IR = IssueResource.getInstance(graph);
1383 issues.add(new L0Issue(description, IR.Issue, subject));
1387 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1388 public static List<Issue> relationValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1390 Layer0 L0 = Layer0.getInstance(graph);
1392 List<Issue> issues = null;
1394 for(Statement stm : graph.getStatements(resource, L0.IsWeaklyRelatedTo)) {
1395 Resource predicate = stm.getPredicate();
1396 Resource object = stm.getObject();
1397 if(!isRelation(graph, L0, predicate)) {
1398 issues = reportInconsistency(graph, resource, "The predicate of a statement must be a relation: " + NameUtils.toString(graph, stm), issues);
1400 if(graph.isInstanceOf(predicate, L0.FunctionalRelation)) {
1401 if(graph.getObjects(resource, predicate).size() > 1)
1402 issues = reportInconsistency(graph, resource,
1404 NameUtils.getSafeName(graph, predicate)
1405 + " is functional.", issues);
1408 Collection<Resource> domain = graph.getObjects(predicate, L0.HasDomain);
1409 if (!isInstanceOfAny(graph, resource, domain, true)) {
1410 StringBuilder sb = new StringBuilder()
1411 .append("The domain of ")
1412 .append(NameUtils.getSafeName(graph, predicate))
1413 .append(" relation is ");
1414 orString(graph, sb, domain).append(".");
1415 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1419 Collection<Resource> range = graph.getObjects(predicate, L0.HasRange);
1420 if (!isInstanceOfAny(graph, object, range, true) && !graph.isInstanceOf(object, L0.SCLValue)) {
1421 StringBuilder sb = new StringBuilder()
1422 .append("The range of ")
1423 .append(NameUtils.getSafeName(graph, predicate))
1424 .append(" relation is ");
1425 orString(graph, sb, range).append(" but current object is ")
1426 .append(NameUtils.getSafeName(graph, object)).append(".");
1427 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1432 return issues != null ? issues : Collections.<Issue>emptyList();
1436 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1437 public static List<Issue> propertyValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1439 List<Issue> issues = null;
1441 Layer0 L0 = Layer0.getInstance(graph);
1442 for(Statement stm : graph.getStatements(resource, L0.HasProperty)) {
1443 Resource subject = stm.getSubject();
1444 Resource predicate = stm.getPredicate();
1445 String error = L0Validations.checkValueType(graph, subject, predicate);
1446 if(error != null) issues = reportInconsistency(graph, subject, error, issues);
1449 return issues != null ? issues : Collections.<Issue>emptyList();
1454 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1455 public static List<Issue> valueValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1457 List<Issue> issues = null;
1459 Layer0 L0 = Layer0.getInstance(graph);
1460 if(graph.hasValue(resource)) {
1461 if(!graph.isInstanceOf(resource, L0.Literal)) {
1462 issues = reportInconsistency(graph, resource,
1463 "Resource has a value but it is not a literal.", issues);
1466 // TODO check that the value is valid for the data type
1470 if(graph.isInstanceOf(resource, L0.Literal)) {
1471 issues = reportInconsistency(graph, resource,
1472 "Resource is a literal but it does not have a value.", issues);
1476 return issues != null ? issues : Collections.<Issue>emptyList();
1481 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1482 public static List<Issue> uriValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1484 List<Issue> issues = null;
1486 Layer0 L0 = Layer0.getInstance(graph);
1487 Resource parent = graph.getPossibleObject(resource, L0.PartOf);
1488 if(parent != null) {
1489 String parentURI = graph.syncRequest(new PossibleURI(parent));
1490 if(parentURI != null) {
1491 String name = graph.getPossibleRelatedValue(resource, L0.HasName);
1493 issues = reportInconsistency(graph, resource, "Resource has a parent with URI but has no valid HasName.", issues);
1498 return issues != null ? issues : Collections.<Issue>emptyList();
1502 private static Resource getPossibleNearestClusterSet(ReadGraph graph, Resource base, Resource resource) throws DatabaseException {
1504 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1505 if(cs.isClusterSet(resource) && !base.equals(resource)) return resource;
1507 Resource nearest = NearestOwnerFinder.getNearestOwner(graph, resource);
1508 if(nearest == null) return null;
1510 return getPossibleNearestClusterSet(graph, base, nearest);
1514 private static boolean quirks(ReadGraph graph, Resource resource) throws DatabaseException {
1516 if(!resource.isPersistent()) return true;
1517 if(graph.isImmutable(resource)) return true;
1518 if(resource.getResourceId() < 0x2000) return true;
1524 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1525 public static List<Issue> clusterValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1527 if(!Development.DEVELOPMENT) return Collections.<Issue>emptyList();
1529 if(quirks(graph, resource)) return Collections.<Issue>emptyList();
1531 List<Issue> issues = null;
1533 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1534 Resource set = cs.getClusterSetOfCluster(resource);
1536 if(set == null) return reportInconsistency(graph, resource, "Resource cluster is not part of any cluster set", issues);
1538 Resource nearestSet = getPossibleNearestClusterSet(graph, resource, resource);
1539 if(nearestSet == null) {
1540 // This means that there is no owner since RootLibrary is a cluster set
1541 return Collections.<Issue>emptyList();
1544 if(!set.equals(nearestSet)) return reportInconsistency(graph, resource, "The cluster set of a resource is not the nearest owner set", issues);
1546 return Collections.<Issue>emptyList();
1550 private static boolean isInstanceOfAny(ReadGraph graph, Resource r, Collection<Resource> types, boolean ifEmpty) throws DatabaseException {
1551 if (types.isEmpty())
1553 for (Resource type : types) {
1554 if (graph.isInstanceOf(r, type)) {
1561 private static StringBuilder orString(ReadGraph graph, StringBuilder sb, Collection<Resource> rs) throws DatabaseException {
1563 boolean first = true;
1564 for (Resource r : rs) {
1568 sb.append(NameUtils.getSafeName(graph, r));
1574 public static boolean isRelation(ReadGraph g, Layer0 l0, Resource relation) throws DatabaseException {
1575 return g.hasStatement(relation, l0.SubrelationOf) || relation == l0.IsWeaklyRelatedTo;
1578 public static boolean isType(ReadGraph g, Layer0 l0, Resource type) throws DatabaseException {
1579 return g.hasStatement(type, l0.Inherits) || type == l0.Entity;
1582 public static Variable buildChildVariable(ReadGraph graph, Variable context, Resource graphChild, Object nodeChild) throws DatabaseException {
1583 VariableBuilder builder = graph.adapt(graphChild, VariableBuilder.class);
1584 return builder.buildChild(graph, context, build(((AbstractVariable)context).node, nodeChild), graphChild);
1587 private static Variable buildPropertyVariable(ReadGraph graph, Variable variable, Resource parentResource, PropertyInfo graphProperty, Object propertyNode) throws DatabaseException {
1588 VariableNode<?> node = variable instanceof AbstractVariable ? build(((AbstractVariable)variable).node, propertyNode) : null;
1589 return graphProperty.builder.buildProperty(graph, variable, node, parentResource, graphProperty.predicate);
1592 static StandardGraphChildVariable createStandardGraphChildVariable(
1593 AbstractVariable parent, Object child) {
1594 return new StandardGraphChildVariable(parent, build(parent.node, child), null);
1597 private static StandardGraphPropertyVariable createStandardGraphPropertyVariable(
1598 ReadGraph graph, AbstractVariable variable, Object nodeProperty) throws DatabaseException {
1599 Resource propertyResource = getPossiblePropertyResource(graph, variable, nodeProperty);
1600 return new StandardGraphPropertyVariable(graph, variable, build(variable.node, nodeProperty), null, propertyResource);
1603 static Map<String, Variable> ensureVariableMap(
1604 Map<String, Variable> map, int size) {
1605 if(map == null) map = new THashMap<String,Variable>(size);
1609 private static PropertyInfo getPropertyInfo(ReadGraph graph, Resource predicate) throws DatabaseException {
1610 return graph.syncRequest(new PropertyInfoRequest(predicate));
1613 @SuppressWarnings("unchecked")
1614 static String getNodeName(AbstractVariable parent, Object child) {
1615 return parent.node.support.manager.getName(child);
1618 @SuppressWarnings("unchecked")
1619 private static Object getNodeValue(final AbstractVariable variable, final Binding binding) throws NodeManagerException, BindingException {
1620 return variable.node.support.manager.getValue(variable.node.node, binding);
1623 @SuppressWarnings("unchecked")
1624 private static void setNodeValue(final AbstractVariable variable, final Object value, final Binding binding) throws NodeManagerException, BindingException {
1625 variable.node.support.manager.setValue(variable.node.node, value, binding);
1628 @SuppressWarnings("unchecked")
1629 private static String getPossiblePropertyURI(AbstractVariable parent, Object node) {
1630 return parent.node.support.manager.getPropertyURI(parent.node.node, node);
1634 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1635 public static Object defaultInstantiateUnder(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1636 return new FunctionImpl2<Resource, Resource, Resource>() {
1637 public Resource apply(Resource container, Resource type) {
1639 WriteGraph graph = (WriteGraph)SCLContext.getCurrent().get("graph");
1641 Layer0 L0 = Layer0.getInstance(graph);
1642 CommonDBUtils.selectClusterSet(graph, container);
1643 Resource result = graph.newResource();
1644 String name = NameUtils.findFreshInstanceName(graph, type, container);
1645 graph.claim(result, L0.InstanceOf, type);
1646 graph.addLiteral(result, L0.HasName, L0.NameOf, name, Bindings.STRING);
1647 graph.claim(container, L0.ConsistsOf, L0.PartOf, result);
1650 } catch (DatabaseException e) {
1651 throw new RuntimeDatabaseException(e);