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.validation.L0Validations;
42 import org.simantics.db.exception.DatabaseException;
43 import org.simantics.db.exception.DoesNotContainValueException;
44 import org.simantics.db.exception.NoSingleResultException;
45 import org.simantics.db.exception.RuntimeDatabaseException;
46 import org.simantics.db.layer0.exception.MissingVariableValueException;
47 import org.simantics.db.layer0.exception.PendingVariableException;
48 import org.simantics.db.layer0.exception.VariableException;
49 import org.simantics.db.layer0.request.PossibleURI;
50 import org.simantics.db.layer0.request.PropertyInfo;
51 import org.simantics.db.layer0.request.PropertyInfoRequest;
52 import org.simantics.db.layer0.request.UnescapedAssertedPropertyMapOfResource;
53 import org.simantics.db.layer0.request.UnescapedMethodMapOfResource;
54 import org.simantics.db.layer0.request.UnescapedPropertyMapOfResource;
55 import org.simantics.db.layer0.scl.CompileResourceValueRequest;
56 import org.simantics.db.layer0.scl.CompileValueRequest;
57 import org.simantics.db.layer0.util.Layer0Utils;
58 import org.simantics.db.layer0.util.PrimitiveValueParser;
59 import org.simantics.db.layer0.variable.AbstractVariable;
60 import org.simantics.db.layer0.variable.ChildVariableMapRequest;
61 import org.simantics.db.layer0.variable.ExternalSetValue;
62 import org.simantics.db.layer0.variable.PropertyVariableMapRequest;
63 import org.simantics.db.layer0.variable.StandardAssertedGraphPropertyVariable;
64 import org.simantics.db.layer0.variable.StandardComposedProperty;
65 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
66 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
67 import org.simantics.db.layer0.variable.SubliteralPropertyVariable;
68 import org.simantics.db.layer0.variable.SubliteralPropertyVariableDeprecated;
69 import org.simantics.db.layer0.variable.ValueAccessor;
70 import org.simantics.db.layer0.variable.Variable;
71 import org.simantics.db.layer0.variable.VariableBuilder;
72 import org.simantics.db.layer0.variable.VariableMap;
73 import org.simantics.db.layer0.variable.VariableMapImpl;
74 import org.simantics.db.layer0.variable.VariableNode;
75 import org.simantics.db.layer0.variable.VariableNodeReadRunnable;
76 import org.simantics.db.layer0.variable.VariableUtils;
77 import org.simantics.db.layer0.variable.Variables;
78 import org.simantics.db.layer0.variable.Variables.NodeStructure;
79 import org.simantics.db.service.ClusteringSupport;
80 import org.simantics.db.service.UndoRedoSupport;
81 import org.simantics.issues.ontology.IssueResource;
82 import org.simantics.layer0.Layer0;
83 import org.simantics.scl.reflection.annotations.SCLValue;
84 import org.simantics.scl.runtime.SCLContext;
85 import org.simantics.scl.runtime.function.Function4;
86 import org.simantics.scl.runtime.function.FunctionImpl1;
87 import org.simantics.scl.runtime.function.FunctionImpl2;
88 import org.simantics.simulator.variable.exceptions.NodeManagerException;
89 import org.simantics.utils.Development;
90 import org.simantics.utils.datastructures.Pair;
91 import org.simantics.utils.strings.StringInputValidator;
93 import gnu.trove.map.hash.THashMap;
94 import gnu.trove.set.hash.THashSet;
98 public static Object standardGetValue1(ReadGraph graph, Variable context) throws DatabaseException {
100 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
103 if(variable.node != null) {
104 Variant value = Variables.requestNodeValue(graph, variable.node);
105 if(Variables.PENDING_NODE_VALUE == value) throw new PendingVariableException("");
106 return value.getValue();
111 if(variable.property.hasEnumerationRange) {
112 Resource object = variable.getRepresents(graph);
113 if(graph.sync(new IsEnumeratedValue(object))) {
114 Layer0 L0 = Layer0.getInstance(graph);
115 if(graph.isInstanceOf(object, L0.Literal)) {
116 return graph.getValue(object);
118 String label = graph.getPossibleRelatedValue2(variable.getRepresents(graph), L0.HasLabel, Bindings.STRING);
119 if(label == null) label = graph.getPossibleRelatedValue(variable.getRepresents(graph), L0.HasName, Bindings.STRING);
120 if(label == null) label = "<no label>";
126 if (variable.isAsserted()) {
127 if (variable.parentResource != null) {
128 Map<String, Pair<PropertyInfo, Resource>> assertions = graph.syncRequest(
129 new UnescapedAssertedPropertyMapOfResource(variable.parentResource),
130 TransientCacheAsyncListener.instance());
132 // NOTE: This optimization assumes the property
133 // variable's representation is the asserted object.
134 Resource object = variable.getPossibleRepresents(graph);
135 if (object != null) {
136 return graph.getValue2(object, variable);
138 for (Pair<PropertyInfo, Resource> assertion : assertions.values()) {
139 if (assertion.first.predicate.equals(variable.property.predicate)) {
140 return graph.getValue2(assertion.second, variable);
147 return graph.getValue2(variable.getRepresents(graph), variable);
149 } catch (NoSingleResultException e) {
150 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
151 } catch (DoesNotContainValueException e) {
152 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
153 } catch (DatabaseException e) {
154 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
159 public static Object standardGetValue2(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
160 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
163 if(variable.node != null) {
165 Variant value = Variables.requestNodeValue(graph, variable.node, binding);
166 if(Variables.PENDING_NODE_VALUE == value) throw new PendingVariableException("");
167 if(value == null) throw new MissingVariableValueException(variable.getPossibleURI(graph));
168 return value.getValue(binding);
169 } catch (AdaptException e) {
170 throw new DatabaseException(e);
176 if(variable.property.hasEnumerationRange) {
177 Resource object = variable.getRepresents(graph);
178 if(graph.sync(new IsEnumeratedValue(object))) {
179 Layer0 L0 = Layer0.getInstance(graph);
180 if(graph.isInstanceOf(object, L0.Literal)) {
181 return graph.getValue(object, binding);
183 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
188 if (variable.isAsserted()) {
189 if (variable.parentResource != null) {
190 Map<String, Pair<PropertyInfo, Resource>> assertions = graph.syncRequest(
191 new UnescapedAssertedPropertyMapOfResource(variable.parentResource),
192 TransientCacheAsyncListener.instance());
194 // NOTE: This optimization assumes the property
195 // variable's representation is the asserted object.
196 Resource object = variable.getPossibleRepresents(graph);
197 if (object != null) {
198 return graph.getValue2(object, variable, binding);
200 for (Pair<PropertyInfo, Resource> assertion : assertions.values()) {
201 if (assertion.first.predicate.equals(variable.property.predicate)) {
202 return graph.getValue2(assertion.second, variable, binding);
209 return graph.getValue2(variable.getRepresents(graph), context, binding);
211 } catch (NoSingleResultException e) {
212 throw new MissingVariableValueException(variable.getPossibleURI(graph));
213 } catch (DoesNotContainValueException e) {
214 throw new MissingVariableValueException(variable.getPossibleURI(graph));
215 } catch (DatabaseException e) {
216 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
221 public static void standardSetValue2(WriteGraph graph, Variable context, final Object value) throws DatabaseException {
223 if(context instanceof StandardGraphPropertyVariable) {
225 final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
228 if(variable.node != null) {
230 final Binding binding = Layer0Utils.getDefaultBinding(graph, variable);
232 final AtomicReference<Object> oldValueRef = new AtomicReference<Object>();
234 variable.node.support.manager.getRealm().syncExec(new Runnable() {
238 oldValueRef.set(getNodeValue(variable, binding));
239 setNodeValue(variable, value, binding);
240 } catch (NodeManagerException e) {
241 throw new RuntimeException(e);
242 } catch (BindingException e) {
243 throw new RuntimeException(e);
247 } catch(RuntimeException e) {
248 if(e.getCause() instanceof NodeManagerException || e.getCause() instanceof BindingException)
249 throw new DatabaseException(e.getCause());
252 } catch (InterruptedException e) {
253 throw new DatabaseException(e);
256 ExternalSetValue ext = new ExternalSetValue(variable.node.support.manager, variable.node.node,
257 oldValueRef.get(), value, binding);
258 graph.getService(UndoRedoSupport.class).addExternalOperation(graph, ext);
265 Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
266 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
268 modifier.apply(graph, context, value, Bindings.getBinding(value.getClass()));
269 } catch (BindingConstructionException e) {
270 throw new DatabaseException(e);
275 public static void standardSetValue3(final WriteGraph graph, Variable context, final Object value, final Binding binding) throws DatabaseException {
278 if(context instanceof StandardGraphPropertyVariable) {
280 final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
283 if(variable.node != null) {
287 variable.node.support.manager.getRealm().syncExec(new Runnable() {
292 Object oldValue = getNodeValue(variable, binding);
293 setNodeValue(variable, value, binding);
294 ExternalSetValue ext = new ExternalSetValue(variable.node.support.manager, variable.node.node, oldValue, value, binding);
295 graph.getService(UndoRedoSupport.class).addExternalOperation(graph, ext);
296 } catch (NodeManagerException | BindingException e) {
297 Logger.defaultLogError(e);
306 } catch (InterruptedException e) {
307 throw new DatabaseException(e);
314 Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
315 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
316 modifier.apply(graph, context, value, binding);
320 public static Datatype getDatatypeFromValue(ReadGraph graph, Variable context) throws DatabaseException {
321 if (context instanceof AbstractVariable) {
322 Binding defaultBinding = ((AbstractVariable)context).getPossibleDefaultBinding(graph);
323 if (defaultBinding != null)
324 return defaultBinding.type();
327 Variant value = context.getVariantValue(graph);
328 if (value.getBinding() == null)
329 throw new DatabaseException("No value binding for " + context.getURI(graph));
331 return value.getBinding().type();
334 @SuppressWarnings("rawtypes")
335 private static class DatatypeGetter implements VariableNodeReadRunnable {
336 final VariableNode node;
340 public DatatypeGetter(VariableNode node) {
344 @SuppressWarnings("unchecked")
348 type = node.support.manager.getDatatype(node.node);
349 } catch (NodeManagerException e) {
354 public String toString() {
355 return "DatatypeGetter(" + node.node + ")";
359 public static Datatype standardGetDatatype(ReadGraph graph, Variable context) throws DatabaseException {
360 if (context instanceof AbstractVariable) {
361 final AbstractVariable variable = (AbstractVariable)context;
362 if (variable.node != null) {
364 DatatypeGetter request = new DatatypeGetter(variable.node);
366 variable.node.support.manager.getRealm().syncExec(request);
368 if (request.exception != null)
369 throw new DatabaseException(request.exception);
372 } catch (InterruptedException e) {
377 return getDatatypeFromValue(graph, context);
380 // @SCLValue(type = "ValueAccessor")
381 // public static ValueAccessor standardValueAccessor = new ValueAccessor() {
384 // public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
385 // return standardGetValue(graph, (StandardGraphPropertyVariable)context);
389 // public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
390 // return standardGetValue(graph, context, binding);
394 // public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
395 // standardSetValue(graph, context, value);
399 // public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
400 // standardSetValue(graph, context, value, binding);
404 // public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
405 // return standardGetDatatype(graph, context);
410 @SCLValue(type = "ValueAccessor")
411 public static ValueAccessor standardValueAccessor = new ValueAccessor() {
414 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
415 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
416 if(accessor != null) return accessor.getValue(graph, context);
418 return standardGetValue1(graph, context);
422 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
423 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
424 if(accessor != null) return accessor.getValue(graph, context, binding);
426 return standardGetValue2(graph, context, binding);
430 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
431 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
432 if(accessor != null) accessor.setValue(graph, context, value);
434 standardSetValue2(graph, context, value);
438 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
439 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
440 if(accessor != null) accessor.setValue(graph, context, value, binding);
442 standardSetValue3(graph, context, value, binding);
446 public Datatype getDatatype(ReadGraph graph, Variable context)
447 throws DatabaseException {
448 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
449 if(accessor != null) return accessor.getDatatype(graph, context);
451 return standardGetDatatype(graph, context);
456 public static Variable getStandardChildDomainPropertyVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
457 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
458 PropertyInfo graphProperty = getPossiblePropertyInfoFromContext(graph, variable, variable.resource, name);
459 return getStandardChildDomainPropertyVariable(graph, context, graphProperty, name);
462 public static Resource getPossiblePropertyResource(ReadGraph graph, AbstractVariable parent, Object node) throws DatabaseException {
463 if(parent != null && parent.node != null && parent.node.node != null && parent.node.support != null) {
464 String propertyURI = getPossiblePropertyURI(parent, node);
465 if(propertyURI != null)
466 return graph.getPossibleResource(propertyURI);
471 public static Variable getStandardChildDomainPropertyVariable(ReadGraph graph, Variable context, PropertyInfo graphProperty, String name) throws DatabaseException {
472 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
473 Object propertyNode = getPossibleNodeProperty(graph, variable, name, true);
474 if(graphProperty != null && graphProperty.builder != null)
475 return buildPropertyVariable(graph, variable, variable.resource, graphProperty, propertyNode);
476 if(propertyNode != null) {
477 // Fallback: try to ask property resource uri from NodeManager
478 return createStandardGraphPropertyVariable(graph, variable, propertyNode);
480 // Final fallback: check types corresponding to
481 // node classification(s) and look for asserted
482 // properties from the URIs specified.
483 if (variable.node != null) {
485 @SuppressWarnings("unchecked")
486 Set<String> classifications = variable.node.support.manager.getClassifications(variable.node.node);
487 if (!classifications.isEmpty()) {
488 for (String uri : classifications) {
489 Resource type = graph.syncRequest(
490 new PossibleResource(uri),
491 TransientCacheAsyncListener.instance());
494 Map<String, Pair<PropertyInfo, Resource>> pm = graph.syncRequest(
495 new UnescapedAssertedPropertyMapOfResource(type),
496 TransientCacheAsyncListener.instance());
497 Pair<PropertyInfo, Resource> pi = pm.get(name);
499 return new StandardAssertedGraphPropertyVariable(graph, context, null, type, pi.first.predicate, pi.second);
503 } catch(NodeManagerException e) {
504 throw new DatabaseException(e);
510 public static Map<String, Variable> getStandardChildDomainPropertyVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
511 // Get properties with null identification
512 return getStandardChildDomainPropertyVariables(graph, context, null, map);
515 public static Map<String, Variable> getStandardChildDomainPropertyVariables(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
517 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
519 Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
520 if(!nodeProperties.isEmpty()) {
522 // Get variables for properties read from the graph
523 Map<String,PropertyInfo> graphProperties = collectPropertyInfosFromContext(graph, variable, variable.resource);
525 Set<String> used = new THashSet<String>(nodeProperties.size());
527 map = ensureVariableMap(map, graphProperties.size() + nodeProperties.size());
529 // Process NodeManager property nodes
530 for(Object nodeProperty : nodeProperties) {
531 String name = getNodeName(variable, nodeProperty);
534 PropertyInfo graphProperty = graphProperties.get(name);
535 if(graphProperty != null && graphProperty.builder != null) {
536 if (classification != null && !graphProperty.hasClassification(classification)) continue;
538 // Combine with identically named graph property
539 map.put(name, buildPropertyVariable(graph, variable, variable.resource, graphProperty, nodeProperty));
543 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
546 // Process graph properties
547 for(PropertyInfo info : graphProperties.values()) {
548 String name = info.name;
549 if(used != null && used.contains(name)) continue;
550 if (classification != null && !info.hasClassification(classification)) continue;
551 if (info.builder != null) {
552 map.put(name, buildPropertyVariable(graph, variable, variable.resource, info, null));
559 if(variable.resource == null) return map;
561 // Only graph properties
562 Collection<Resource> predicates = graph.getPredicates(variable.resource);
563 if(predicates.isEmpty()) return map;
565 map = ensureVariableMap(map, predicates.size());
567 // Process graph properties
568 for(Resource predicate : predicates) {
570 PropertyInfo info = graph.isImmutable(predicate) ?
571 graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
572 graph.syncRequest(new PropertyInfoRequest(predicate));
574 if(!info.isHasProperty) continue;
576 if (classification != null && !info.hasClassification(classification)) continue;
577 if (info.builder != null) {
578 map.put(info.name, buildPropertyVariable(graph, variable, variable.resource, info, null));
589 @SCLValue(type = "VariableMap")
590 public static VariableMap standardChildDomainProperties = new VariableMapImpl() {
593 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
594 return getStandardChildDomainPropertyVariable(graph, context, name);
598 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
599 return getStandardChildDomainPropertyVariables(graph, context, map);
604 @SCLValue(type = "VariableMap")
605 public static VariableMap methodsPropertyDomainProperties = new VariableMapImpl() {
608 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
609 Variable parent = context.getParent(graph);
610 Resource container = parent.getPossibleRepresents(graph);
611 if(container == null)
613 Map<String,Resource> methods = graph.syncRequest(new UnescapedMethodMapOfResource(container));
614 Resource predicate = methods.get(name);
615 if(predicate != null) {
616 Layer0 L0 = Layer0.getInstance(graph);
617 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(L0.Entity_method));
618 Resource value = graph.getSingleObject(container, predicate);
619 return new StandardGraphPropertyVariable(context, null, container, info, value);
625 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
626 Variable parent = context.getParent(graph);
627 Resource container = parent.getPossibleRepresents(graph);
628 if(container == null)
629 return Collections.emptyMap();
630 Map<String,Resource> methods = graph.syncRequest(new UnescapedMethodMapOfResource(container));
631 for(Map.Entry<String, Resource> entry : methods.entrySet()) {
632 String name = entry.getKey();
633 Resource predicate = entry.getValue();
634 Layer0 L0 = Layer0.getInstance(graph);
635 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(L0.Entity_method));
636 Resource value = graph.getSingleObject(container, predicate);
637 if(map == null) map = new HashMap<>();
638 map.put(name, new StandardGraphPropertyVariable(context, null, container, info, value));
645 public static Variable getStandardPropertyDomainPropertyVariableFromValue(ReadGraph graph, Variable context, String name) throws DatabaseException {
647 if(context instanceof StandardGraphPropertyVariable) {
648 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
649 Resource literal = variable.getPossibleRepresents(graph);
650 Object propertyNode = getPossibleNodeProperty(graph, variable, name, false);
652 if(literal != null) {
653 Variable result = getPossiblePropertyFromContext(graph, variable, literal, name, propertyNode);
654 if(result != null) return result;
657 Variable result = getPossibleSubliteralPropertyFromContext(graph, variable, name);
658 if(result != null) return result;
659 result = getPossiblePropertyFromContext(graph, variable, variable.property.predicate, name, propertyNode);
660 if (result != null) return result;
662 // Get possible property from NodeManager
663 if (propertyNode != null)
664 return createStandardGraphPropertyVariable(graph, variable, propertyNode);
666 } else if (context instanceof StandardGraphChildVariable) {
667 return standardChildDomainProperties.getVariable(graph, context, name);
669 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
674 public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
676 if(context instanceof StandardGraphPropertyVariable) {
677 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
678 map = collectPropertiesFromContext(graph, variable, variable.property.predicate, map);
679 if (variable.parentResource != null) {
680 Resource literal = graph.getPossibleObject(variable.parentResource, variable.property.predicate);
681 if(literal != null) map=collectPropertiesFromContext(graph, variable, literal, map);
682 map=collectSubliteralProperties(graph, variable, map);
685 // Get properties from VariableNode
686 map = getStandardNodePropertyVariables(graph, context, map);
688 } else if (context instanceof StandardGraphChildVariable) {
689 return standardChildDomainProperties.getVariables(graph, context, map);
691 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
696 public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
698 if(context instanceof StandardGraphPropertyVariable) {
699 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
700 map = collectPropertiesFromContext(graph, variable, variable.property.predicate, classification, map);
701 if (variable.parentResource != null) {
702 Resource literal = graph.getPossibleObject(variable.parentResource, variable.property.predicate);
703 if(literal != null) map=collectPropertiesFromContext(graph, variable, literal, classification, map);
706 // Get properties from VariableNode
707 map = getStandardNodePropertyVariables(graph, context, map);
709 } else if (context instanceof StandardGraphChildVariable) {
710 return standardChildDomainProperties.getVariables(graph, context, map);
712 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
717 @SCLValue(type = "VariableMap")
718 public static VariableMap standardPropertyDomainProperties = new VariableMapImpl() {
720 VariableMap getValueVariableMap(ReadGraph graph, Variable context) throws DatabaseException {
721 Resource represents = context.getPossibleRepresents(graph);
722 if(represents == null) return null;
724 VariableMap map = graph.isImmutable(represents) ?
725 graph.syncRequest(new PropertyVariableMapRequest(represents), TransientCacheListener.<VariableMap>instance()) :
726 (VariableMap)graph.getPossibleRelatedValue2(represents, Layer0.getInstance(graph).domainProperties, represents);
728 if(map == standardPropertyDomainProperties) return null;
734 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
735 VariableMap valueMap = getValueVariableMap(graph, context);
736 if(valueMap != null) return valueMap.getVariable(graph, context, name);
737 return getStandardPropertyDomainPropertyVariableFromValue(graph, context, name);
741 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
742 VariableMap valueMap = getValueVariableMap(graph, context);
743 if(valueMap != null) return valueMap.getVariables(graph, context, map);
744 else return getStandardPropertyDomainPropertyVariablesFromValue(graph, context, map);
748 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
749 VariableMap valueMap = getValueVariableMap(graph, context);
750 if(valueMap != null) return valueMap.getVariables(graph, context, classification, map);
751 else return getStandardPropertyDomainPropertyVariablesFromValue(graph, context, classification, map);
756 public static Resource getPossibleGraphChild(ReadGraph graph, Variable variable, String name) throws DatabaseException {
757 Resource resource = variable.getPossibleRepresents(graph);
758 if(resource == null) return null;
759 Map<String, Resource> graphChildren = graph.syncRequest(new UnescapedChildMapOfResource(resource));
760 return graphChildren.get(name);
763 public static Map<String,Resource> getPossibleGraphChildren(ReadGraph graph, Variable variable) throws DatabaseException {
764 Resource resource = variable.getPossibleRepresents(graph);
765 if(resource == null) return Collections.emptyMap();
766 return graph.syncRequest(new UnescapedChildMapOfResource(resource));
769 public static Object getPossibleNodeChild(ReadGraph graph, Variable variable, String name) throws DatabaseException {
770 if (!(variable instanceof AbstractVariable)) return null;
771 VariableNode<?> node = ((AbstractVariable)variable).node;
772 if(node == null) return null;
773 NodeStructure structure = Variables.requestNodeStructure(graph, node);
774 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
775 return structure.children.get(name);
778 public static Collection<Object> getPossibleNodeChildren(ReadGraph graph, Variable variable) throws DatabaseException {
779 if (!(variable instanceof AbstractVariable)) return null;
780 VariableNode<?> node = ((AbstractVariable)variable).node;
781 if(node == null) return Collections.emptyList();
782 NodeStructure structure = Variables.requestNodeStructure(graph, node);
783 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
784 return structure.children.values();
787 public static Object getPossibleNodeProperty(ReadGraph graph, Variable variable, String name, boolean throwPending) throws DatabaseException {
788 if (!(variable instanceof AbstractVariable)) return null;
789 VariableNode<?> node = ((AbstractVariable)variable).node;
790 if(node == null) return null;
791 NodeStructure structure = Variables.requestNodeStructure(graph, node);
792 if(throwPending && Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
793 return structure.properties.get(name);
796 public static Collection<Object> getPossibleNodeProperties(ReadGraph graph, Variable variable) throws DatabaseException {
797 if (!(variable instanceof AbstractVariable)) return null;
798 VariableNode<?> node = ((AbstractVariable)variable).node;
799 if(node == null) return Collections.emptyList();
800 NodeStructure structure = Variables.requestNodeStructure(graph, node);
801 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
802 return structure.properties.values();
805 @SuppressWarnings({ "rawtypes", "unchecked" })
806 public static VariableNode build(VariableNode parent, Object node) {
807 if(node == null) return null;
808 return new VariableNode(parent.support, node);
812 public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
813 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
817 public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, Resource graphChild, String name) throws DatabaseException {
818 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, graphChild, name);
822 public static Map<String, Variable> getStandardChildDomainChildVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
823 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
827 public static Map<String, Variable> getStandardChildDomainChildVariables(ReadGraph graph, Variable context, Map<String,Resource> graphChildren, Map<String, Variable> map) throws DatabaseException {
828 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, graphChildren, map);
832 * Get a map of child Variables from a node manager-based Variable, combined with the existing variables in #map.
833 * @param graph The read graph.
834 * @param context The parent Variable.
835 * @param map A map of variables into which the new variables are merged.
836 * @return A map from variable names to instances
837 * @throws DatabaseException
839 public static Map<String, Variable> getStandardNodeChildVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
840 AbstractVariable variable = (AbstractVariable)context;
841 if (variable.node == null) return map;
843 Collection<Object> nodeChildren = getPossibleNodeChildren(graph, variable);
844 if (nodeChildren.isEmpty()) return map;
846 map = ensureVariableMap(map, nodeChildren.size());
848 for(Object nodeChild : nodeChildren) {
849 String name = getNodeName(variable, nodeChild);
850 if (!map.containsKey(name))
851 map.put(name, createStandardGraphChildVariable(variable, nodeChild));
858 * Get a map of property Variables from a node manager-based Variable, combined with the existing variables in #map.
859 * @param graph The read graph.
860 * @param context The parent Variable.
861 * @param map A map of variables into which the new variables are merged.
862 * @return A map from variable names to instances
863 * @throws DatabaseException
865 public static Map<String, Variable> getStandardNodePropertyVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
866 AbstractVariable variable = (AbstractVariable)context;
867 if (variable.node == null) return map;
869 Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
870 if (nodeProperties.isEmpty()) return map;
872 map = ensureVariableMap(map, nodeProperties.size());
874 for(Object nodeProperty : nodeProperties) {
875 String name = getNodeName(variable, nodeProperty);
876 if (!map.containsKey(name)) {
877 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
884 @SCLValue(type = "VariableMap")
885 public static VariableMap standardChildDomainChildren = new VariableMapImpl() {
888 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
889 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
893 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
894 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
899 @SCLValue(type = "VariableMap")
900 public static VariableMap standardPropertyDomainChildren = new VariableMapImpl() {
903 * Get a possible non-standard VariableMap defined in the graph.
904 * @param graph The graph
905 * @param context The context node
906 * @return A non-standard VariableMap instance for the context node,
907 * or null, if not defined or defined as this instance.
908 * @throws DatabaseException
910 VariableMap getValueVariableMap(ReadGraph graph, Variable context) throws DatabaseException {
911 Resource represents = context.getPossibleRepresents(graph);
912 if(represents == null) return null;
913 VariableMap map = graph.syncRequest(new ChildVariableMapRequest(represents));
914 if(map == standardPropertyDomainChildren) return null;
919 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
920 // Delegate call to a non-standard variable map?
921 VariableMap valueMap = getValueVariableMap(graph, context);
922 if(valueMap != null) return valueMap.getVariable(graph, context, name);
924 if(context instanceof StandardGraphPropertyVariable) {
925 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
926 Datatype dt = variable.getDatatype(graph);
927 if (dt instanceof ArrayType) {
928 ChildReference ref = getPossibleIndexReference(name);
930 return new SubliteralPropertyVariableDeprecated(variable, ref);
933 // Check for a child node provided by the NodeManager
934 if (variable.node != null) {
935 Object childNode = getPossibleNodeChild(graph, variable, name);
936 if (childNode != null)
937 return createStandardGraphChildVariable(variable, childNode);
939 return standardChildDomainChildren.getVariable(graph, context, name);
940 } else if (context instanceof StandardGraphChildVariable) {
941 return standardChildDomainChildren.getVariable(graph, context, name);
943 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
948 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
949 // Delegate call to a non-standard variable map?
950 VariableMap valueMap = getValueVariableMap(graph, context);
951 if(valueMap != null) return valueMap.getVariables(graph, context, map);
953 if(context instanceof StandardGraphPropertyVariable) {
954 // Get child variables provided by the NodeManager
955 Map<String, Variable> result = getStandardNodeChildVariables(graph, context, map);
956 return standardChildDomainChildren.getVariables(graph, context, result);
957 } else if (context instanceof StandardGraphChildVariable) {
958 return standardChildDomainChildren.getVariables(graph, context, map);
960 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
966 protected static ChildReference getPossibleIndexReference(String name) {
967 if (name.startsWith("i-")) {
969 int index = Integer.parseInt(name.substring(2));
970 return new IndexReference(index);
971 } catch (NumberFormatException e) {}
976 protected static ValueAccessor getPossiblePropertyValueAccessor(ReadGraph graph, StandardGraphPropertyVariable variable) throws DatabaseException {
977 if(variable.property == null) return null;
978 return variable.property.valueAccessor;
979 // return graph.syncRequest(new PropertyValueAccessorRequest(variable.property), TransientCacheAsyncListener.<ValueAccessor>instance());
980 // return graph.syncRequest(new PossibleRelatedValueImplied2<ValueAccessor>(variable.property, Layer0.getInstance(graph).valueAccessor));
983 public static ValueAccessor getPossibleValueValueAccessor(ReadGraph graph, Variable variable) throws DatabaseException {
984 Resource value = variable.getPossibleRepresents(graph);
985 if(value == null) return null;
986 //return graph.syncRequest(new PropertyValueAccessorRequest(value));
987 return graph.syncRequest(new PossibleRelatedValueImplied2<ValueAccessor>(value, Layer0.getInstance(graph).valueAccessor));
990 public static PropertyInfo getPossiblePropertyInfoFromContext(ReadGraph graph, Variable variable, Resource context, String name) throws DatabaseException {
991 if(context == null) return null;
992 Map<String, PropertyInfo> predicates = graph.syncRequest(new UnescapedPropertyMapOfResource(context));
993 return predicates.get(name);
996 public static Variable getPossiblePropertyFromContext(ReadGraph graph, Variable variable, Resource context, String name, Object propertyNode) throws DatabaseException {
997 PropertyInfo info = getPossiblePropertyInfoFromContext(graph, variable, context, name);
998 if(info == null || info.builder == null) return null;
999 return buildPropertyVariable(graph, variable, context, info, propertyNode);
1002 public static Variable getPossibleSubliteralPropertyFromContext(ReadGraph graph, StandardGraphPropertyVariable variable, String name) throws DatabaseException {
1004 Resource predicate = variable.property.predicate;
1005 if(predicate == null) return null;
1007 PropertyInfo info = getPropertyInfo(graph, predicate);
1008 Pair<Resource, ChildReference> p = info.subliteralPredicates.get(name);
1009 if(p == null) return null;
1011 return new SubliteralPropertyVariable(graph, variable, p.first, p.second);
1015 public static Map<String, PropertyInfo> collectPropertyInfosFromContext(ReadGraph graph, Variable variable, Resource context) throws DatabaseException {
1016 if(context == null) return Collections.emptyMap();
1017 return graph.isImmutable(context) ?
1018 graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance()) :
1019 graph.syncRequest(new UnescapedPropertyMapOfResource(context));
1022 public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, Map<String, Variable> map) throws DatabaseException {
1024 Map<String,PropertyInfo> properties = graph.isImmutable(context) ?
1025 graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance()) :
1026 graph.syncRequest(new UnescapedPropertyMapOfResource(context));
1028 if(properties.isEmpty()) return map;
1030 map = ensureVariableMap(map, properties.size());
1032 for(PropertyInfo info : properties.values()) {
1033 String name = info.name;
1034 if (info.builder != null) {
1035 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1044 public static Map<String, Variable> collectSubliteralProperties(ReadGraph graph, StandardGraphPropertyVariable variable, Map<String, Variable> map) throws DatabaseException {
1046 Resource predicate = variable.property.predicate;
1047 if(predicate == null) return map;
1049 PropertyInfo info = getPropertyInfo(graph, predicate);
1050 if(info.subliteralPredicates.isEmpty()) return map;
1052 map = ensureVariableMap(map, info.subliteralPredicates.size());
1054 for(Map.Entry<String, Pair<Resource, ChildReference>> entry : info.subliteralPredicates.entrySet()) {
1055 String key = entry.getKey();
1056 Pair<Resource, ChildReference> p = entry.getValue();
1057 if(map == null) map = new THashMap<String,Variable>();
1058 map.put(key, new SubliteralPropertyVariable(graph, variable, p.first, p.second));
1065 public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, String classification, Map<String, Variable> map) throws DatabaseException {
1067 if(graph.isImmutable(context)) {
1069 Map<String,PropertyInfo> properties = graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance());
1070 for(PropertyInfo info : properties.values()) {
1072 if(info.classifications.contains(classification) && info.builder != null) {
1073 String name = info.name;
1074 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1075 if(map == null) map = new THashMap<String,Variable>();
1083 Collection<Resource> predicates = graph.getPredicates(context);
1085 if(predicates.isEmpty()) return map;
1087 map = ensureVariableMap(map, predicates.size());
1089 for(Resource predicate : predicates) {
1091 PropertyInfo info = graph.isImmutable(predicate) ?
1092 graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
1093 graph.syncRequest(new PropertyInfoRequest(predicate));
1095 if(!info.isHasProperty) continue;
1097 if(info.classifications.contains(classification) && info.builder != null) {
1098 String name = info.name;
1099 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1100 if(map == null) map = new THashMap<String,Variable>();
1112 @SCLValue(type = "ReadGraph -> Resource -> a -> String")
1113 public static String entityLabel(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1114 if(context instanceof Resource) {
1115 return NameUtils.getSafeLabel(graph, ((Resource)context));
1116 } else if (context instanceof Variable) {
1117 Variable parent = ((Variable)context).getParent(graph);
1118 Resource represents = parent.getRepresents(graph);
1119 return NameUtils.getSafeLabel(graph, represents);
1121 throw new DatabaseException("Unknown context " + context);
1125 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1126 public static Object listResources(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1127 return ListUtils.toList(graph, resource);
1130 @SCLValue(type = "ReadGraph -> Resource -> Variable -> [String]")
1131 public static List<String> standardClassifications(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1132 ArrayList<String> result = new ArrayList<String>();
1133 Resource predicate = context.getParent(graph).getPossiblePredicateResource(graph);
1134 if(predicate != null) {
1135 for(Resource type : graph.getTypes(predicate)) {
1136 String uri = graph.getPossibleURI(type);
1137 if(uri != null) result.add(uri);
1143 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1144 public static Boolean standardValidValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1145 return Boolean.TRUE;
1148 @SCLValue(type = "ReadGraph -> Resource -> a -> StringInputValidator")
1149 public static StringInputValidator standardValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1150 return StringInputValidator.PASS;
1153 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1154 public static Boolean standardRequiredValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1155 return Boolean.FALSE;
1158 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Boolean")
1159 public static Boolean standardDefaultValue(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1160 Variable property = context.getParent(graph);
1161 if(property instanceof StandardGraphPropertyVariable) {
1162 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)property;
1163 if (variable.parentResource != null) {
1164 Statement stm = graph.getPossibleStatement(variable.parentResource, variable.property.predicate);
1165 return stm != null && stm.isAsserted(variable.parentResource);
1168 return Boolean.FALSE;
1171 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1172 public static Boolean standardReadOnlyValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1173 return Boolean.FALSE;
1176 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1177 public static Object resourceAsValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1181 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1182 public static Object functionApplication(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1183 return Functions.exec(graph, resource, graph, resource, context);
1186 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1187 public static Object computeExpression(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1188 if(context instanceof Variable) {
1189 return CompileValueRequest.compileAndEvaluate(graph, (Variable)context);
1190 } if (context instanceof Resource) {
1191 return CompileResourceValueRequest.compileAndEvaluate(graph, (Resource)converter);
1193 throw new IllegalStateException("Unknown context " + context);
1197 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1198 public static Object composedPropertyValue(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1199 if(context instanceof Variable) {
1200 return new StandardComposedProperty();
1201 } if (context instanceof Resource) {
1202 return new StandardComposedProperty();
1204 throw new IllegalStateException("Unknown context " + context);
1208 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1209 public static Object numberInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1211 class Validator extends FunctionImpl1<String, String> {
1213 private final Datatype datatype;
1215 public Validator(Datatype datatype) {
1216 this.datatype = datatype;
1220 public String apply(String input) {
1222 if(datatype == null) return null;
1226 if(datatype instanceof NumberType) {
1228 Number number = (Number)PrimitiveValueParser.parse(input, datatype);
1229 NumberType nt = (NumberType)datatype;
1230 Range r = nt.getRange();
1232 if(!r.contains(number)) return "Value is out of valid range";
1237 } catch (NumberFormatException e) {
1238 return "Not a valid floating-point number";
1239 } catch (IllegalArgumentException e) {
1240 return "Not a valid floating-point number";
1247 if(context instanceof Variable) {
1249 Variable variable = (Variable)context;
1250 Variable property = variable.getParent(graph);
1251 Datatype datatype = property.getPossibleDatatype(graph);
1252 return new Validator(datatype);
1254 } else if (context instanceof Resource) {
1256 Layer0 L0 = Layer0.getInstance(graph);
1257 Resource literal = (Resource)context;
1258 Datatype datatype = graph.getRelatedValue(literal, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
1259 return new Validator(datatype);
1263 return new Validator(null);
1269 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1270 public static Object booleanInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1272 return new FunctionImpl1<String, String>() {
1275 public String apply(String input) {
1277 String lower = input.toLowerCase();
1278 if("true".equals(lower) || "false".equals(lower)) return null;
1280 return "Not a valid boolean: " + input;
1288 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Resource")
1289 public static Resource hasStandardResource(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1290 Variable parent = context.getParent(graph);
1291 if(parent instanceof StandardGraphChildVariable) {
1292 StandardGraphChildVariable variable = (StandardGraphChildVariable)parent;
1293 return variable.resource;
1299 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1300 public static Object valueWithoutBinding(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1302 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1304 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1305 Layer0 L0 = Layer0.getInstance(graph);
1306 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel);
1309 if (variable.parentResource == null)
1310 throw new VariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").");
1313 return graph.getRelatedValue2(variable.parentResource, variable.property.predicate, variable);
1314 } catch (NoSingleResultException e) {
1315 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1316 } catch (DoesNotContainValueException e) {
1317 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1322 @SCLValue(type = "ReadGraph -> Variable -> Binding -> a")
1323 public static Object valueWithBinding(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
1325 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1327 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1328 Layer0 L0 = Layer0.getInstance(graph);
1329 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
1332 if (variable.parentResource == null)
1333 throw new VariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").");
1336 return graph.getRelatedValue2(variable.parentResource, variable.property.predicate, variable);
1337 } catch (NoSingleResultException e) {
1338 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1339 } catch (DoesNotContainValueException e) {
1340 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1345 @SCLValue(type = "WriteGraph -> Variable -> a -> Binding -> b")
1346 public static Object valueSetterWithBinding(WriteGraph graph, Variable variable, Object value, Binding binding) throws DatabaseException {
1348 Function4<WriteGraph, Variable, Object, Object, String> modifier = variable.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
1349 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
1350 modifier.apply(graph, variable, value, binding);
1355 static class L0Issue extends StandardIssue {
1357 private final String description;
1359 public L0Issue(String description, Resource type, Resource ... contexts) {
1360 super(type, contexts);
1361 this.description = description;
1365 public Resource write(WriteGraph graph, Resource source) throws DatabaseException {
1366 Layer0 L0 = Layer0.getInstance(graph);
1367 IssueResource IR = IssueResource.getInstance(graph);
1368 Resource issue = super.write(graph, source);
1369 graph.claim(issue, IR.Issue_HasSeverity, IR.Severity_Fatal);
1370 graph.addLiteral(issue, L0.HasDescription, L0.HasDescription_Inverse, description, Bindings.STRING);
1376 private static List<Issue> reportInconsistency(ReadGraph graph, Resource subject, String description, List<Issue> issues) throws DatabaseException {
1377 if(issues == null) issues = new ArrayList<Issue>();
1378 System.err.println("Change set validation reports the following issue: " + NameUtils.getSafeName(graph, subject, true) + ": " + description);
1379 IssueResource IR = IssueResource.getInstance(graph);
1380 issues.add(new L0Issue(description, IR.Issue, subject));
1384 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1385 public static List<Issue> relationValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1387 Layer0 L0 = Layer0.getInstance(graph);
1389 List<Issue> issues = null;
1391 for(Statement stm : graph.getStatements(resource, L0.IsWeaklyRelatedTo)) {
1392 Resource predicate = stm.getPredicate();
1393 Resource object = stm.getObject();
1394 if(!isRelation(graph, L0, predicate)) {
1395 issues = reportInconsistency(graph, resource, "The predicate of a statement must be a relation: " + NameUtils.toString(graph, stm), issues);
1397 if(graph.isInstanceOf(predicate, L0.FunctionalRelation)) {
1398 if(graph.getObjects(resource, predicate).size() > 1)
1399 issues = reportInconsistency(graph, resource,
1401 NameUtils.getSafeName(graph, predicate)
1402 + " is functional.", issues);
1405 Collection<Resource> domain = graph.getObjects(predicate, L0.HasDomain);
1406 if (!isInstanceOfAny(graph, resource, domain, true)) {
1407 StringBuilder sb = new StringBuilder()
1408 .append("The domain of ")
1409 .append(NameUtils.getSafeName(graph, predicate))
1410 .append(" relation is ");
1411 orString(graph, sb, domain).append(".");
1412 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1416 Collection<Resource> range = graph.getObjects(predicate, L0.HasRange);
1417 if (!isInstanceOfAny(graph, object, range, true) && !graph.isInstanceOf(object, L0.SCLValue)) {
1418 StringBuilder sb = new StringBuilder()
1419 .append("The range of ")
1420 .append(NameUtils.getSafeName(graph, predicate))
1421 .append(" relation is ");
1422 orString(graph, sb, range).append(" but current object is ")
1423 .append(NameUtils.getSafeName(graph, object)).append(".");
1424 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1429 return issues != null ? issues : Collections.<Issue>emptyList();
1433 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1434 public static List<Issue> propertyValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1436 List<Issue> issues = null;
1438 Layer0 L0 = Layer0.getInstance(graph);
1439 for(Statement stm : graph.getStatements(resource, L0.HasProperty)) {
1440 Resource subject = stm.getSubject();
1441 Resource predicate = stm.getPredicate();
1442 String error = L0Validations.checkValueType(graph, subject, predicate);
1443 if(error != null) issues = reportInconsistency(graph, subject, error, issues);
1446 return issues != null ? issues : Collections.<Issue>emptyList();
1451 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1452 public static List<Issue> valueValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1454 List<Issue> issues = null;
1456 Layer0 L0 = Layer0.getInstance(graph);
1457 if(graph.hasValue(resource)) {
1458 if(!graph.isInstanceOf(resource, L0.Literal)) {
1459 issues = reportInconsistency(graph, resource,
1460 "Resource has a value but it is not a literal.", issues);
1463 // TODO check that the value is valid for the data type
1467 if(graph.isInstanceOf(resource, L0.Literal)) {
1468 issues = reportInconsistency(graph, resource,
1469 "Resource is a literal but it does not have a value.", issues);
1473 return issues != null ? issues : Collections.<Issue>emptyList();
1478 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1479 public static List<Issue> uriValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1481 List<Issue> issues = null;
1483 Layer0 L0 = Layer0.getInstance(graph);
1484 Resource parent = graph.getPossibleObject(resource, L0.PartOf);
1485 if(parent != null) {
1486 String parentURI = graph.syncRequest(new PossibleURI(parent));
1487 if(parentURI != null) {
1488 String name = graph.getPossibleRelatedValue(resource, L0.HasName);
1490 issues = reportInconsistency(graph, resource, "Resource has a parent with URI but has no valid HasName.", issues);
1495 return issues != null ? issues : Collections.<Issue>emptyList();
1499 private static Resource getPossibleNearestClusterSet(ReadGraph graph, Resource base, Resource resource) throws DatabaseException {
1501 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1502 if(cs.isClusterSet(resource) && !base.equals(resource)) return resource;
1504 Resource nearest = CommonDBUtils.getNearestOwner(graph, Collections.singletonList(resource));
1505 if(nearest == null) return null;
1507 return getPossibleNearestClusterSet(graph, base, nearest);
1511 private static boolean quirks(ReadGraph graph, Resource resource) throws DatabaseException {
1513 if(!resource.isPersistent()) return true;
1514 if(graph.isImmutable(resource)) return true;
1515 if(resource.getResourceId() < 0x2000) return true;
1521 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1522 public static List<Issue> clusterValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1524 if(!Development.DEVELOPMENT) return Collections.<Issue>emptyList();
1526 if(quirks(graph, resource)) return Collections.<Issue>emptyList();
1528 List<Issue> issues = null;
1530 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1531 Resource set = cs.getClusterSetOfCluster(resource);
1533 if(set == null) return reportInconsistency(graph, resource, "Resource cluster is not part of any cluster set", issues);
1535 Resource nearestSet = getPossibleNearestClusterSet(graph, resource, resource);
1536 if(nearestSet == null) {
1537 // This means that there is no owner since RootLibrary is a cluster set
1538 return Collections.<Issue>emptyList();
1541 if(!set.equals(nearestSet)) return reportInconsistency(graph, resource, "The cluster set of a resource is not the nearest owner set", issues);
1543 return Collections.<Issue>emptyList();
1547 private static boolean isInstanceOfAny(ReadGraph graph, Resource r, Collection<Resource> types, boolean ifEmpty) throws DatabaseException {
1548 if (types.isEmpty())
1550 for (Resource type : types) {
1551 if (graph.isInstanceOf(r, type)) {
1558 private static StringBuilder orString(ReadGraph graph, StringBuilder sb, Collection<Resource> rs) throws DatabaseException {
1560 boolean first = true;
1561 for (Resource r : rs) {
1565 sb.append(NameUtils.getSafeName(graph, r));
1571 public static boolean isRelation(ReadGraph g, Layer0 l0, Resource relation) throws DatabaseException {
1572 return g.hasStatement(relation, l0.SubrelationOf) || relation == l0.IsWeaklyRelatedTo;
1575 public static boolean isType(ReadGraph g, Layer0 l0, Resource type) throws DatabaseException {
1576 return g.hasStatement(type, l0.Inherits) || type == l0.Entity;
1579 public static Variable buildChildVariable(ReadGraph graph, Variable context, Resource graphChild, Object nodeChild) throws DatabaseException {
1580 VariableBuilder builder = graph.adapt(graphChild, VariableBuilder.class);
1581 return builder.buildChild(graph, context, build(((AbstractVariable)context).node, nodeChild), graphChild);
1584 private static Variable buildPropertyVariable(ReadGraph graph, Variable variable, Resource parentResource, PropertyInfo graphProperty, Object propertyNode) throws DatabaseException {
1585 VariableNode<?> node = variable instanceof AbstractVariable ? build(((AbstractVariable)variable).node, propertyNode) : null;
1586 return graphProperty.builder.buildProperty(graph, variable, node, parentResource, graphProperty.predicate);
1589 static StandardGraphChildVariable createStandardGraphChildVariable(
1590 AbstractVariable parent, Object child) {
1591 return new StandardGraphChildVariable(parent, build(parent.node, child), null);
1594 private static StandardGraphPropertyVariable createStandardGraphPropertyVariable(
1595 ReadGraph graph, AbstractVariable variable, Object nodeProperty) throws DatabaseException {
1596 Resource propertyResource = getPossiblePropertyResource(graph, variable, nodeProperty);
1597 return new StandardGraphPropertyVariable(graph, variable, build(variable.node, nodeProperty), null, propertyResource);
1600 static Map<String, Variable> ensureVariableMap(
1601 Map<String, Variable> map, int size) {
1602 if(map == null) map = new THashMap<String,Variable>(size);
1606 private static PropertyInfo getPropertyInfo(ReadGraph graph, Resource predicate) throws DatabaseException {
1607 return graph.syncRequest(new PropertyInfoRequest(predicate));
1610 @SuppressWarnings("unchecked")
1611 static String getNodeName(AbstractVariable parent, Object child) {
1612 return parent.node.support.manager.getName(child);
1615 @SuppressWarnings("unchecked")
1616 private static Object getNodeValue(final AbstractVariable variable, final Binding binding) throws NodeManagerException, BindingException {
1617 return variable.node.support.manager.getValue(variable.node.node, binding);
1620 @SuppressWarnings("unchecked")
1621 private static void setNodeValue(final AbstractVariable variable, final Object value, final Binding binding) throws NodeManagerException, BindingException {
1622 variable.node.support.manager.setValue(variable.node.node, value, binding);
1625 @SuppressWarnings("unchecked")
1626 private static String getPossiblePropertyURI(AbstractVariable parent, Object node) {
1627 return parent.node.support.manager.getPropertyURI(parent.node.node, node);
1631 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1632 public static Object defaultInstantiateUnder(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1633 return new FunctionImpl2<Resource, Resource, Resource>() {
1634 public Resource apply(Resource container, Resource type) {
1636 WriteGraph graph = (WriteGraph)SCLContext.getCurrent().get("graph");
1638 Layer0 L0 = Layer0.getInstance(graph);
1639 CommonDBUtils.selectClusterSet(graph, container);
1640 Resource result = graph.newResource();
1641 String name = NameUtils.findFreshInstanceName(graph, type, container);
1642 graph.claim(result, L0.InstanceOf, type);
1643 graph.addLiteral(result, L0.HasName, L0.NameOf, name, Bindings.STRING);
1644 graph.claim(container, L0.ConsistsOf, L0.PartOf, result);
1647 } catch (DatabaseException e) {
1648 throw new RuntimeDatabaseException(e);