1 package org.simantics.db.layer0.function;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
9 import java.util.concurrent.atomic.AtomicReference;
11 import org.simantics.databoard.Bindings;
12 import org.simantics.databoard.accessor.reference.ChildReference;
13 import org.simantics.databoard.accessor.reference.IndexReference;
14 import org.simantics.databoard.adapter.AdaptException;
15 import org.simantics.databoard.binding.Binding;
16 import org.simantics.databoard.binding.error.BindingConstructionException;
17 import org.simantics.databoard.binding.error.BindingException;
18 import org.simantics.databoard.binding.mutable.Variant;
19 import org.simantics.databoard.type.ArrayType;
20 import org.simantics.databoard.type.Datatype;
21 import org.simantics.databoard.type.NumberType;
22 import org.simantics.databoard.util.Range;
23 import org.simantics.db.Issue;
24 import org.simantics.db.ReadGraph;
25 import org.simantics.db.Resource;
26 import org.simantics.db.Statement;
27 import org.simantics.db.WriteGraph;
28 import org.simantics.db.common.issue.StandardIssue;
29 import org.simantics.db.common.primitiverequest.PossibleRelatedValueImplied2;
30 import org.simantics.db.common.primitiverequest.PossibleResource;
31 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
32 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
33 import org.simantics.db.common.request.IsEnumeratedValue;
34 import org.simantics.db.common.uri.UnescapedChildMapOfResource;
35 import org.simantics.db.common.utils.CommonDBUtils;
36 import org.simantics.db.common.utils.Functions;
37 import org.simantics.db.common.utils.ListUtils;
38 import org.simantics.db.common.utils.Logger;
39 import org.simantics.db.common.utils.NameUtils;
40 import org.simantics.db.common.validation.L0Validations;
41 import org.simantics.db.exception.DatabaseException;
42 import org.simantics.db.exception.DoesNotContainValueException;
43 import org.simantics.db.exception.NoSingleResultException;
44 import org.simantics.db.layer0.exception.MissingVariableValueException;
45 import org.simantics.db.layer0.exception.PendingVariableException;
46 import org.simantics.db.layer0.exception.VariableException;
47 import org.simantics.db.layer0.request.PossibleURI;
48 import org.simantics.db.layer0.request.PropertyInfo;
49 import org.simantics.db.layer0.request.PropertyInfoRequest;
50 import org.simantics.db.layer0.request.UnescapedAssertedPropertyMapOfResource;
51 import org.simantics.db.layer0.request.UnescapedPropertyMapOfResource;
52 import org.simantics.db.layer0.scl.CompileResourceValueRequest;
53 import org.simantics.db.layer0.scl.CompileValueRequest;
54 import org.simantics.db.layer0.util.Layer0Utils;
55 import org.simantics.db.layer0.util.PrimitiveValueParser;
56 import org.simantics.db.layer0.variable.AbstractVariable;
57 import org.simantics.db.layer0.variable.ChildVariableMapRequest;
58 import org.simantics.db.layer0.variable.ExternalSetValue;
59 import org.simantics.db.layer0.variable.PropertyVariableMapRequest;
60 import org.simantics.db.layer0.variable.StandardAssertedGraphPropertyVariable;
61 import org.simantics.db.layer0.variable.StandardComposedProperty;
62 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
63 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
64 import org.simantics.db.layer0.variable.SubliteralPropertyVariable;
65 import org.simantics.db.layer0.variable.SubliteralPropertyVariableDeprecated;
66 import org.simantics.db.layer0.variable.ValueAccessor;
67 import org.simantics.db.layer0.variable.Variable;
68 import org.simantics.db.layer0.variable.VariableBuilder;
69 import org.simantics.db.layer0.variable.VariableMap;
70 import org.simantics.db.layer0.variable.VariableMapImpl;
71 import org.simantics.db.layer0.variable.VariableNode;
72 import org.simantics.db.layer0.variable.VariableNodeReadRunnable;
73 import org.simantics.db.layer0.variable.VariableUtils;
74 import org.simantics.db.layer0.variable.Variables;
75 import org.simantics.db.layer0.variable.Variables.NodeStructure;
76 import org.simantics.db.service.ClusteringSupport;
77 import org.simantics.db.service.UndoRedoSupport;
78 import org.simantics.issues.ontology.IssueResource;
79 import org.simantics.layer0.Layer0;
80 import org.simantics.scl.reflection.annotations.SCLValue;
81 import org.simantics.scl.runtime.function.Function4;
82 import org.simantics.scl.runtime.function.FunctionImpl1;
83 import org.simantics.simulator.variable.exceptions.NodeManagerException;
84 import org.simantics.utils.Development;
85 import org.simantics.utils.datastructures.Pair;
86 import org.simantics.utils.strings.StringInputValidator;
88 import gnu.trove.map.hash.THashMap;
89 import gnu.trove.set.hash.THashSet;
93 public static Object standardGetValue1(ReadGraph graph, Variable context) throws DatabaseException {
95 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
98 if(variable.node != null) {
99 Variant value = Variables.requestNodeValue(graph, variable.node);
100 if(Variables.PENDING_NODE_VALUE == value) throw new PendingVariableException("");
101 return value.getValue();
106 if(variable.property.hasEnumerationRange) {
107 Resource object = variable.getRepresents(graph);
108 if(graph.sync(new IsEnumeratedValue(object))) {
109 Layer0 L0 = Layer0.getInstance(graph);
110 if(graph.isInstanceOf(object, L0.Literal)) {
111 return graph.getValue(object);
113 String label = graph.getPossibleRelatedValue2(variable.getRepresents(graph), L0.HasLabel, Bindings.STRING);
114 if(label == null) label = graph.getPossibleRelatedValue(variable.getRepresents(graph), L0.HasName, Bindings.STRING);
115 if(label == null) label = "<no label>";
121 if (variable.isAsserted()) {
122 if (variable.parentResource != null) {
123 Map<String, Pair<PropertyInfo, Resource>> assertions = graph.syncRequest(
124 new UnescapedAssertedPropertyMapOfResource(variable.parentResource),
125 TransientCacheAsyncListener.instance());
127 // NOTE: This optimization assumes the property
128 // variable's representation is the asserted object.
129 Resource object = variable.getPossibleRepresents(graph);
130 if (object != null) {
131 return graph.getValue2(object, variable);
133 for (Pair<PropertyInfo, Resource> assertion : assertions.values()) {
134 if (assertion.first.predicate.equals(variable.property.predicate)) {
135 return graph.getValue2(assertion.second, variable);
142 return graph.getValue2(variable.getRepresents(graph), variable);
144 } catch (NoSingleResultException e) {
145 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
146 } catch (DoesNotContainValueException e) {
147 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
148 } catch (DatabaseException e) {
149 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
154 public static Object standardGetValue2(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
155 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
158 if(variable.node != null) {
160 Variant value = Variables.requestNodeValue(graph, variable.node, binding);
161 if(Variables.PENDING_NODE_VALUE == value) throw new PendingVariableException("");
162 if(value == null) throw new MissingVariableValueException(variable.getPossibleURI(graph));
163 return value.getValue(binding);
164 } catch (AdaptException e) {
165 throw new DatabaseException(e);
171 if(variable.property.hasEnumerationRange) {
172 Resource object = variable.getRepresents(graph);
173 if(graph.sync(new IsEnumeratedValue(object))) {
174 Layer0 L0 = Layer0.getInstance(graph);
175 if(graph.isInstanceOf(object, L0.Literal)) {
176 return graph.getValue(object, binding);
178 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
183 if (variable.isAsserted()) {
184 if (variable.parentResource != null) {
185 Map<String, Pair<PropertyInfo, Resource>> assertions = graph.syncRequest(
186 new UnescapedAssertedPropertyMapOfResource(variable.parentResource),
187 TransientCacheAsyncListener.instance());
189 // NOTE: This optimization assumes the property
190 // variable's representation is the asserted object.
191 Resource object = variable.getPossibleRepresents(graph);
192 if (object != null) {
193 return graph.getValue2(object, variable, binding);
195 for (Pair<PropertyInfo, Resource> assertion : assertions.values()) {
196 if (assertion.first.predicate.equals(variable.property.predicate)) {
197 return graph.getValue2(assertion.second, variable, binding);
204 return graph.getValue2(variable.getRepresents(graph), context, binding);
206 } catch (NoSingleResultException e) {
207 throw new MissingVariableValueException(variable.getPossibleURI(graph));
208 } catch (DoesNotContainValueException e) {
209 throw new MissingVariableValueException(variable.getPossibleURI(graph));
210 } catch (DatabaseException e) {
211 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
216 public static void standardSetValue2(WriteGraph graph, Variable context, final Object value) throws DatabaseException {
218 if(context instanceof StandardGraphPropertyVariable) {
220 final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
223 if(variable.node != null) {
225 final Binding binding = Layer0Utils.getDefaultBinding(graph, variable);
227 final AtomicReference<Object> oldValueRef = new AtomicReference<Object>();
229 variable.node.support.manager.getRealm().syncExec(new Runnable() {
233 oldValueRef.set(getNodeValue(variable, binding));
234 setNodeValue(variable, value, binding);
235 } catch (NodeManagerException e) {
236 throw new RuntimeException(e);
237 } catch (BindingException e) {
238 throw new RuntimeException(e);
242 } catch(RuntimeException e) {
243 if(e.getCause() instanceof NodeManagerException || e.getCause() instanceof BindingException)
244 throw new DatabaseException(e.getCause());
247 } catch (InterruptedException e) {
248 throw new DatabaseException(e);
251 ExternalSetValue ext = new ExternalSetValue(variable.node.support.manager, variable.node.node,
252 oldValueRef.get(), value, binding);
253 graph.getService(UndoRedoSupport.class).addExternalOperation(graph, ext);
260 Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
261 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
263 modifier.apply(graph, context, value, Bindings.getBinding(value.getClass()));
264 } catch (BindingConstructionException e) {
265 throw new DatabaseException(e);
270 public static void standardSetValue3(final WriteGraph graph, Variable context, final Object value, final Binding binding) throws DatabaseException {
273 if(context instanceof StandardGraphPropertyVariable) {
275 final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
278 if(variable.node != null) {
282 variable.node.support.manager.getRealm().syncExec(new Runnable() {
287 Object oldValue = getNodeValue(variable, binding);
288 setNodeValue(variable, value, binding);
289 ExternalSetValue ext = new ExternalSetValue(variable.node.support.manager, variable.node.node, oldValue, value, binding);
290 graph.getService(UndoRedoSupport.class).addExternalOperation(graph, ext);
291 } catch (NodeManagerException | BindingException e) {
292 Logger.defaultLogError(e);
301 } catch (InterruptedException e) {
302 throw new DatabaseException(e);
309 Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
310 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
311 modifier.apply(graph, context, value, binding);
315 public static Datatype getDatatypeFromValue(ReadGraph graph, Variable context) throws DatabaseException {
316 if (context instanceof AbstractVariable) {
317 Binding defaultBinding = ((AbstractVariable)context).getPossibleDefaultBinding(graph);
318 if (defaultBinding != null)
319 return defaultBinding.type();
322 Variant value = context.getVariantValue(graph);
323 if (value.getBinding() == null)
324 throw new DatabaseException("No value binding for " + context.getURI(graph));
326 return value.getBinding().type();
329 @SuppressWarnings("rawtypes")
330 private static class DatatypeGetter implements VariableNodeReadRunnable {
331 final VariableNode node;
335 public DatatypeGetter(VariableNode node) {
339 @SuppressWarnings("unchecked")
343 type = node.support.manager.getDatatype(node.node);
344 } catch (NodeManagerException e) {
349 public String toString() {
350 return "DatatypeGetter(" + node.node + ")";
354 public static Datatype standardGetDatatype(ReadGraph graph, Variable context) throws DatabaseException {
355 if (context instanceof AbstractVariable) {
356 final AbstractVariable variable = (AbstractVariable)context;
357 if (variable.node != null) {
359 DatatypeGetter request = new DatatypeGetter(variable.node);
361 variable.node.support.manager.getRealm().syncExec(request);
363 if (request.exception != null)
364 throw new DatabaseException(request.exception);
367 } catch (InterruptedException e) {
372 return getDatatypeFromValue(graph, context);
375 // @SCLValue(type = "ValueAccessor")
376 // public static ValueAccessor standardValueAccessor = new ValueAccessor() {
379 // public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
380 // return standardGetValue(graph, (StandardGraphPropertyVariable)context);
384 // public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
385 // return standardGetValue(graph, context, binding);
389 // public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
390 // standardSetValue(graph, context, value);
394 // public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
395 // standardSetValue(graph, context, value, binding);
399 // public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
400 // return standardGetDatatype(graph, context);
405 @SCLValue(type = "ValueAccessor")
406 public static ValueAccessor standardValueAccessor = new ValueAccessor() {
409 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
410 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
411 if(accessor != null) return accessor.getValue(graph, context);
413 return standardGetValue1(graph, context);
417 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
418 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
419 if(accessor != null) return accessor.getValue(graph, context, binding);
421 return standardGetValue2(graph, context, binding);
425 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
426 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
427 if(accessor != null) accessor.setValue(graph, context, value);
429 standardSetValue2(graph, context, value);
433 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
434 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
435 if(accessor != null) accessor.setValue(graph, context, value, binding);
437 standardSetValue3(graph, context, value, binding);
441 public Datatype getDatatype(ReadGraph graph, Variable context)
442 throws DatabaseException {
443 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
444 if(accessor != null) return accessor.getDatatype(graph, context);
446 return standardGetDatatype(graph, context);
451 public static Variable getStandardChildDomainPropertyVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
452 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
453 PropertyInfo graphProperty = getPossiblePropertyInfoFromContext(graph, variable, variable.resource, name);
454 return getStandardChildDomainPropertyVariable(graph, context, graphProperty, name);
457 public static Resource getPossiblePropertyResource(ReadGraph graph, AbstractVariable parent, Object node) throws DatabaseException {
458 if(parent != null && parent.node != null && parent.node.node != null && parent.node.support != null) {
459 String propertyURI = getPossiblePropertyURI(parent, node);
460 if(propertyURI != null)
461 return graph.getPossibleResource(propertyURI);
466 public static Variable getStandardChildDomainPropertyVariable(ReadGraph graph, Variable context, PropertyInfo graphProperty, String name) throws DatabaseException {
467 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
468 Object propertyNode = getPossibleNodeProperty(graph, variable, name, true);
469 if(graphProperty != null && graphProperty.builder != null)
470 return buildPropertyVariable(graph, variable, variable.resource, graphProperty, propertyNode);
471 if(propertyNode != null) {
472 // Fallback: try to ask property resource uri from NodeManager
473 return createStandardGraphPropertyVariable(graph, variable, propertyNode);
475 // Final fallback: check types corresponding to
476 // node classification(s) and look for asserted
477 // properties from the URIs specified.
478 if (variable.node != null) {
480 @SuppressWarnings("unchecked")
481 Set<String> classifications = variable.node.support.manager.getClassifications(variable.node.node);
482 if (!classifications.isEmpty()) {
483 for (String uri : classifications) {
484 Resource type = graph.syncRequest(
485 new PossibleResource(uri),
486 TransientCacheAsyncListener.instance());
489 Map<String, Pair<PropertyInfo, Resource>> pm = graph.syncRequest(
490 new UnescapedAssertedPropertyMapOfResource(type),
491 TransientCacheAsyncListener.instance());
492 Pair<PropertyInfo, Resource> pi = pm.get(name);
494 return new StandardAssertedGraphPropertyVariable(graph, context, null, type, pi.first.predicate, pi.second);
498 } catch(NodeManagerException e) {
499 throw new DatabaseException(e);
505 public static Map<String, Variable> getStandardChildDomainPropertyVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
506 // Get properties with null identification
507 return getStandardChildDomainPropertyVariables(graph, context, null, map);
510 public static Map<String, Variable> getStandardChildDomainPropertyVariables(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
512 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
514 Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
515 if(!nodeProperties.isEmpty()) {
517 // Get variables for properties read from the graph
518 Map<String,PropertyInfo> graphProperties = collectPropertyInfosFromContext(graph, variable, variable.resource);
520 Set<String> used = new THashSet<String>(nodeProperties.size());
522 map = ensureVariableMap(map, graphProperties.size() + nodeProperties.size());
524 // Process NodeManager property nodes
525 for(Object nodeProperty : nodeProperties) {
526 String name = getNodeName(variable, nodeProperty);
529 PropertyInfo graphProperty = graphProperties.get(name);
530 if(graphProperty != null && graphProperty.builder != null) {
531 if (classification != null && !graphProperty.hasClassification(classification)) continue;
533 // Combine with identically named graph property
534 map.put(name, buildPropertyVariable(graph, variable, variable.resource, graphProperty, nodeProperty));
538 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
541 // Process graph properties
542 for(PropertyInfo info : graphProperties.values()) {
543 String name = info.name;
544 if(used != null && used.contains(name)) continue;
545 if (classification != null && !info.hasClassification(classification)) continue;
546 if (info.builder != null) {
547 map.put(name, buildPropertyVariable(graph, variable, variable.resource, info, null));
554 if(variable.resource == null) return map;
556 // Only graph properties
557 Collection<Resource> predicates = graph.getPredicates(variable.resource);
558 if(predicates.isEmpty()) return map;
560 map = ensureVariableMap(map, predicates.size());
562 // Process graph properties
563 for(Resource predicate : predicates) {
565 PropertyInfo info = graph.isImmutable(predicate) ?
566 graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
567 graph.syncRequest(new PropertyInfoRequest(predicate));
569 if(!info.isHasProperty) continue;
571 if (classification != null && !info.hasClassification(classification)) continue;
572 if (info.builder != null) {
573 map.put(info.name, buildPropertyVariable(graph, variable, variable.resource, info, null));
584 @SCLValue(type = "VariableMap")
585 public static VariableMap standardChildDomainProperties = new VariableMapImpl() {
588 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
589 return getStandardChildDomainPropertyVariable(graph, context, name);
593 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
594 return getStandardChildDomainPropertyVariables(graph, context, map);
599 public static Variable getStandardPropertyDomainPropertyVariableFromValue(ReadGraph graph, Variable context, String name) throws DatabaseException {
601 if(context instanceof StandardGraphPropertyVariable) {
602 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
603 Resource literal = variable.getPossibleRepresents(graph);
604 Object propertyNode = getPossibleNodeProperty(graph, variable, name, false);
606 if(literal != null) {
607 Variable result = getPossiblePropertyFromContext(graph, variable, literal, name, propertyNode);
608 if(result != null) return result;
611 Variable result = getPossibleSubliteralPropertyFromContext(graph, variable, name);
612 if(result != null) return result;
613 result = getPossiblePropertyFromContext(graph, variable, variable.property.predicate, name, propertyNode);
614 if (result != null) return result;
616 // Get possible property from NodeManager
617 if (propertyNode != null)
618 return createStandardGraphPropertyVariable(graph, variable, propertyNode);
620 } else if (context instanceof StandardGraphChildVariable) {
621 return standardChildDomainProperties.getVariable(graph, context, name);
623 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
628 public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
630 if(context instanceof StandardGraphPropertyVariable) {
631 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
632 map = collectPropertiesFromContext(graph, variable, variable.property.predicate, map);
633 if (variable.parentResource != null) {
634 Resource literal = graph.getPossibleObject(variable.parentResource, variable.property.predicate);
635 if(literal != null) map=collectPropertiesFromContext(graph, variable, literal, map);
636 map=collectSubliteralProperties(graph, variable, map);
639 // Get properties from VariableNode
640 map = getStandardNodePropertyVariables(graph, context, map);
642 } else if (context instanceof StandardGraphChildVariable) {
643 return standardChildDomainProperties.getVariables(graph, context, map);
645 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
650 public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
652 if(context instanceof StandardGraphPropertyVariable) {
653 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
654 map = collectPropertiesFromContext(graph, variable, variable.property.predicate, classification, map);
655 if (variable.parentResource != null) {
656 Resource literal = graph.getPossibleObject(variable.parentResource, variable.property.predicate);
657 if(literal != null) map=collectPropertiesFromContext(graph, variable, literal, classification, map);
660 // Get properties from VariableNode
661 map = getStandardNodePropertyVariables(graph, context, map);
663 } else if (context instanceof StandardGraphChildVariable) {
664 return standardChildDomainProperties.getVariables(graph, context, map);
666 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
671 @SCLValue(type = "VariableMap")
672 public static VariableMap standardPropertyDomainProperties = new VariableMapImpl() {
674 VariableMap getValueVariableMap(ReadGraph graph, Variable context) throws DatabaseException {
675 Resource represents = context.getPossibleRepresents(graph);
676 if(represents == null) return null;
678 VariableMap map = graph.isImmutable(represents) ?
679 graph.syncRequest(new PropertyVariableMapRequest(represents), TransientCacheListener.<VariableMap>instance()) :
680 (VariableMap)graph.getPossibleRelatedValue2(represents, Layer0.getInstance(graph).domainProperties, represents);
682 if(map == standardPropertyDomainProperties) return null;
688 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
689 VariableMap valueMap = getValueVariableMap(graph, context);
690 if(valueMap != null) return valueMap.getVariable(graph, context, name);
691 return getStandardPropertyDomainPropertyVariableFromValue(graph, context, name);
695 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
696 VariableMap valueMap = getValueVariableMap(graph, context);
697 if(valueMap != null) return valueMap.getVariables(graph, context, map);
698 else return getStandardPropertyDomainPropertyVariablesFromValue(graph, context, map);
702 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
703 VariableMap valueMap = getValueVariableMap(graph, context);
704 if(valueMap != null) return valueMap.getVariables(graph, context, classification, map);
705 else return getStandardPropertyDomainPropertyVariablesFromValue(graph, context, classification, map);
710 public static Resource getPossibleGraphChild(ReadGraph graph, Variable variable, String name) throws DatabaseException {
711 Resource resource = variable.getPossibleRepresents(graph);
712 if(resource == null) return null;
713 Map<String, Resource> graphChildren = graph.syncRequest(new UnescapedChildMapOfResource(resource));
714 return graphChildren.get(name);
717 public static Map<String,Resource> getPossibleGraphChildren(ReadGraph graph, Variable variable) throws DatabaseException {
718 Resource resource = variable.getPossibleRepresents(graph);
719 if(resource == null) return Collections.emptyMap();
720 return graph.syncRequest(new UnescapedChildMapOfResource(resource));
723 public static Object getPossibleNodeChild(ReadGraph graph, Variable variable, String name) throws DatabaseException {
724 if (!(variable instanceof AbstractVariable)) return null;
725 VariableNode<?> node = ((AbstractVariable)variable).node;
726 if(node == null) return null;
727 NodeStructure structure = Variables.requestNodeStructure(graph, node);
728 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
729 return structure.children.get(name);
732 public static Collection<Object> getPossibleNodeChildren(ReadGraph graph, Variable variable) throws DatabaseException {
733 if (!(variable instanceof AbstractVariable)) return null;
734 VariableNode<?> node = ((AbstractVariable)variable).node;
735 if(node == null) return Collections.emptyList();
736 NodeStructure structure = Variables.requestNodeStructure(graph, node);
737 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
738 return structure.children.values();
741 public static Object getPossibleNodeProperty(ReadGraph graph, Variable variable, String name, boolean throwPending) throws DatabaseException {
742 if (!(variable instanceof AbstractVariable)) return null;
743 VariableNode<?> node = ((AbstractVariable)variable).node;
744 if(node == null) return null;
745 NodeStructure structure = Variables.requestNodeStructure(graph, node);
746 if(throwPending && Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
747 return structure.properties.get(name);
750 public static Collection<Object> getPossibleNodeProperties(ReadGraph graph, Variable variable) throws DatabaseException {
751 if (!(variable instanceof AbstractVariable)) return null;
752 VariableNode<?> node = ((AbstractVariable)variable).node;
753 if(node == null) return Collections.emptyList();
754 NodeStructure structure = Variables.requestNodeStructure(graph, node);
755 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
756 return structure.properties.values();
759 @SuppressWarnings({ "rawtypes", "unchecked" })
760 public static VariableNode build(VariableNode parent, Object node) {
761 if(node == null) return null;
762 return new VariableNode(parent.support, node);
766 public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
767 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
771 public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, Resource graphChild, String name) throws DatabaseException {
772 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, graphChild, name);
776 public static Map<String, Variable> getStandardChildDomainChildVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
777 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
781 public static Map<String, Variable> getStandardChildDomainChildVariables(ReadGraph graph, Variable context, Map<String,Resource> graphChildren, Map<String, Variable> map) throws DatabaseException {
782 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, graphChildren, map);
786 * Get a map of child Variables from a node manager-based Variable, combined with the existing variables in #map.
787 * @param graph The read graph.
788 * @param context The parent Variable.
789 * @param map A map of variables into which the new variables are merged.
790 * @return A map from variable names to instances
791 * @throws DatabaseException
793 public static Map<String, Variable> getStandardNodeChildVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
794 AbstractVariable variable = (AbstractVariable)context;
795 if (variable.node == null) return map;
797 Collection<Object> nodeChildren = getPossibleNodeChildren(graph, variable);
798 if (nodeChildren.isEmpty()) return map;
800 map = ensureVariableMap(map, nodeChildren.size());
802 for(Object nodeChild : nodeChildren) {
803 String name = getNodeName(variable, nodeChild);
804 if (!map.containsKey(name))
805 map.put(name, createStandardGraphChildVariable(variable, nodeChild));
812 * Get a map of property Variables from a node manager-based Variable, combined with the existing variables in #map.
813 * @param graph The read graph.
814 * @param context The parent Variable.
815 * @param map A map of variables into which the new variables are merged.
816 * @return A map from variable names to instances
817 * @throws DatabaseException
819 public static Map<String, Variable> getStandardNodePropertyVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
820 AbstractVariable variable = (AbstractVariable)context;
821 if (variable.node == null) return map;
823 Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
824 if (nodeProperties.isEmpty()) return map;
826 map = ensureVariableMap(map, nodeProperties.size());
828 for(Object nodeProperty : nodeProperties) {
829 String name = getNodeName(variable, nodeProperty);
830 if (!map.containsKey(name)) {
831 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
838 @SCLValue(type = "VariableMap")
839 public static VariableMap standardChildDomainChildren = new VariableMapImpl() {
842 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
843 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
847 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
848 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
853 @SCLValue(type = "VariableMap")
854 public static VariableMap standardPropertyDomainChildren = new VariableMapImpl() {
857 * Get a possible non-standard VariableMap defined in the graph.
858 * @param graph The graph
859 * @param context The context node
860 * @return A non-standard VariableMap instance for the context node,
861 * or null, if not defined or defined as this instance.
862 * @throws DatabaseException
864 VariableMap getValueVariableMap(ReadGraph graph, Variable context) throws DatabaseException {
865 Resource represents = context.getPossibleRepresents(graph);
866 if(represents == null) return null;
867 VariableMap map = graph.syncRequest(new ChildVariableMapRequest(represents));
868 if(map == standardPropertyDomainChildren) return null;
873 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
874 // Delegate call to a non-standard variable map?
875 VariableMap valueMap = getValueVariableMap(graph, context);
876 if(valueMap != null) return valueMap.getVariable(graph, context, name);
878 if(context instanceof StandardGraphPropertyVariable) {
879 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
880 Datatype dt = variable.getDatatype(graph);
881 if (dt instanceof ArrayType) {
882 ChildReference ref = getPossibleIndexReference(name);
884 return new SubliteralPropertyVariableDeprecated(variable, ref);
887 // Check for a child node provided by the NodeManager
888 if (variable.node != null) {
889 Object childNode = getPossibleNodeChild(graph, variable, name);
890 if (childNode != null)
891 return createStandardGraphChildVariable(variable, childNode);
893 return standardChildDomainChildren.getVariable(graph, context, name);
894 } else if (context instanceof StandardGraphChildVariable) {
895 return standardChildDomainChildren.getVariable(graph, context, name);
897 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
902 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
903 // Delegate call to a non-standard variable map?
904 VariableMap valueMap = getValueVariableMap(graph, context);
905 if(valueMap != null) return valueMap.getVariables(graph, context, map);
907 if(context instanceof StandardGraphPropertyVariable) {
908 // Get child variables provided by the NodeManager
909 Map<String, Variable> result = getStandardNodeChildVariables(graph, context, map);
910 return standardChildDomainChildren.getVariables(graph, context, result);
911 } else if (context instanceof StandardGraphChildVariable) {
912 return standardChildDomainChildren.getVariables(graph, context, map);
914 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
920 protected static ChildReference getPossibleIndexReference(String name) {
921 if (name.startsWith("i-")) {
923 int index = Integer.parseInt(name.substring(2));
924 return new IndexReference(index);
925 } catch (NumberFormatException e) {}
930 protected static ValueAccessor getPossiblePropertyValueAccessor(ReadGraph graph, StandardGraphPropertyVariable variable) throws DatabaseException {
931 if(variable.property == null) return null;
932 return variable.property.valueAccessor;
933 // return graph.syncRequest(new PropertyValueAccessorRequest(variable.property), TransientCacheAsyncListener.<ValueAccessor>instance());
934 // return graph.syncRequest(new PossibleRelatedValueImplied2<ValueAccessor>(variable.property, Layer0.getInstance(graph).valueAccessor));
937 public static ValueAccessor getPossibleValueValueAccessor(ReadGraph graph, Variable variable) throws DatabaseException {
938 Resource value = variable.getPossibleRepresents(graph);
939 if(value == null) return null;
940 //return graph.syncRequest(new PropertyValueAccessorRequest(value));
941 return graph.syncRequest(new PossibleRelatedValueImplied2<ValueAccessor>(value, Layer0.getInstance(graph).valueAccessor));
944 public static PropertyInfo getPossiblePropertyInfoFromContext(ReadGraph graph, Variable variable, Resource context, String name) throws DatabaseException {
945 if(context == null) return null;
946 Map<String, PropertyInfo> predicates = graph.syncRequest(new UnescapedPropertyMapOfResource(context));
947 return predicates.get(name);
950 public static Variable getPossiblePropertyFromContext(ReadGraph graph, Variable variable, Resource context, String name, Object propertyNode) throws DatabaseException {
951 PropertyInfo info = getPossiblePropertyInfoFromContext(graph, variable, context, name);
952 if(info == null || info.builder == null) return null;
953 return buildPropertyVariable(graph, variable, context, info, propertyNode);
956 public static Variable getPossibleSubliteralPropertyFromContext(ReadGraph graph, StandardGraphPropertyVariable variable, String name) throws DatabaseException {
958 Resource predicate = variable.property.predicate;
959 if(predicate == null) return null;
961 PropertyInfo info = getPropertyInfo(graph, predicate);
962 Pair<Resource, ChildReference> p = info.subliteralPredicates.get(name);
963 if(p == null) return null;
965 return new SubliteralPropertyVariable(graph, variable, p.first, p.second);
969 public static Map<String, PropertyInfo> collectPropertyInfosFromContext(ReadGraph graph, Variable variable, Resource context) throws DatabaseException {
970 if(context == null) return Collections.emptyMap();
971 return graph.isImmutable(context) ?
972 graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance()) :
973 graph.syncRequest(new UnescapedPropertyMapOfResource(context));
976 public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, Map<String, Variable> map) throws DatabaseException {
978 Map<String,PropertyInfo> properties = graph.isImmutable(context) ?
979 graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance()) :
980 graph.syncRequest(new UnescapedPropertyMapOfResource(context));
982 if(properties.isEmpty()) return map;
984 map = ensureVariableMap(map, properties.size());
986 for(PropertyInfo info : properties.values()) {
987 String name = info.name;
988 if (info.builder != null) {
989 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
998 public static Map<String, Variable> collectSubliteralProperties(ReadGraph graph, StandardGraphPropertyVariable variable, Map<String, Variable> map) throws DatabaseException {
1000 Resource predicate = variable.property.predicate;
1001 if(predicate == null) return map;
1003 PropertyInfo info = getPropertyInfo(graph, predicate);
1004 if(info.subliteralPredicates.isEmpty()) return map;
1006 map = ensureVariableMap(map, info.subliteralPredicates.size());
1008 for(Map.Entry<String, Pair<Resource, ChildReference>> entry : info.subliteralPredicates.entrySet()) {
1009 String key = entry.getKey();
1010 Pair<Resource, ChildReference> p = entry.getValue();
1011 if(map == null) map = new THashMap<String,Variable>();
1012 map.put(key, new SubliteralPropertyVariable(graph, variable, p.first, p.second));
1019 public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, String classification, Map<String, Variable> map) throws DatabaseException {
1021 if(graph.isImmutable(context)) {
1023 Map<String,PropertyInfo> properties = graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance());
1024 for(PropertyInfo info : properties.values()) {
1026 if(info.classifications.contains(classification) && info.builder != null) {
1027 String name = info.name;
1028 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1029 if(map == null) map = new THashMap<String,Variable>();
1037 Collection<Resource> predicates = graph.getPredicates(context);
1039 if(predicates.isEmpty()) return map;
1041 map = ensureVariableMap(map, predicates.size());
1043 for(Resource predicate : predicates) {
1045 PropertyInfo info = graph.isImmutable(predicate) ?
1046 graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
1047 graph.syncRequest(new PropertyInfoRequest(predicate));
1049 if(!info.isHasProperty) continue;
1051 if(info.classifications.contains(classification) && info.builder != null) {
1052 String name = info.name;
1053 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1054 if(map == null) map = new THashMap<String,Variable>();
1066 @SCLValue(type = "ReadGraph -> Resource -> a -> String")
1067 public static String entityLabel(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1068 if(context instanceof Resource) {
1069 return NameUtils.getSafeLabel(graph, ((Resource)context));
1070 } else if (context instanceof Variable) {
1071 Variable parent = ((Variable)context).getParent(graph);
1072 Resource represents = parent.getRepresents(graph);
1073 return NameUtils.getSafeLabel(graph, represents);
1075 throw new DatabaseException("Unknown context " + context);
1079 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1080 public static Object listResources(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1081 return ListUtils.toList(graph, resource);
1084 @SCLValue(type = "ReadGraph -> Resource -> Variable -> [String]")
1085 public static List<String> standardClassifications(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1086 ArrayList<String> result = new ArrayList<String>();
1087 Resource predicate = context.getParent(graph).getPossiblePredicateResource(graph);
1088 if(predicate != null) {
1089 for(Resource type : graph.getTypes(predicate)) {
1090 String uri = graph.getPossibleURI(type);
1091 if(uri != null) result.add(uri);
1097 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1098 public static Boolean standardValidValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1099 return Boolean.TRUE;
1102 @SCLValue(type = "ReadGraph -> Resource -> a -> StringInputValidator")
1103 public static StringInputValidator standardValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1104 return StringInputValidator.PASS;
1107 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1108 public static Boolean standardRequiredValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1109 return Boolean.FALSE;
1112 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Boolean")
1113 public static Boolean standardDefaultValue(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1114 Variable property = context.getParent(graph);
1115 if(property instanceof StandardGraphPropertyVariable) {
1116 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)property;
1117 if (variable.parentResource != null) {
1118 Statement stm = graph.getPossibleStatement(variable.parentResource, variable.property.predicate);
1119 return stm != null && stm.isAsserted(variable.parentResource);
1122 return Boolean.FALSE;
1125 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1126 public static Boolean standardReadOnlyValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1127 return Boolean.FALSE;
1130 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1131 public static Object resourceAsValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1135 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1136 public static Object functionApplication(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1137 return Functions.exec(graph, resource, graph, resource, context);
1140 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1141 public static Object computeExpression(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1142 if(context instanceof Variable) {
1143 return CompileValueRequest.compileAndEvaluate(graph, (Variable)context);
1144 } if (context instanceof Resource) {
1145 return CompileResourceValueRequest.compileAndEvaluate(graph, (Resource)converter);
1147 throw new IllegalStateException("Unknown context " + context);
1151 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1152 public static Object composedPropertyValue(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1153 if(context instanceof Variable) {
1154 return new StandardComposedProperty();
1155 } if (context instanceof Resource) {
1156 return new StandardComposedProperty();
1158 throw new IllegalStateException("Unknown context " + context);
1162 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1163 public static Object numberInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1165 class Validator extends FunctionImpl1<String, String> {
1167 private final Datatype datatype;
1169 public Validator(Datatype datatype) {
1170 this.datatype = datatype;
1174 public String apply(String input) {
1176 if(datatype == null) return null;
1180 if(datatype instanceof NumberType) {
1182 Number number = (Number)PrimitiveValueParser.parse(input, datatype);
1183 NumberType nt = (NumberType)datatype;
1184 Range r = nt.getRange();
1186 if(!r.contains(number)) return "Value is out of valid range";
1191 } catch (NumberFormatException e) {
1192 return "Not a valid floating-point number";
1193 } catch (IllegalArgumentException e) {
1194 return "Not a valid floating-point number";
1201 if(context instanceof Variable) {
1203 Variable variable = (Variable)context;
1204 Variable property = variable.getParent(graph);
1205 Datatype datatype = property.getPossibleDatatype(graph);
1206 return new Validator(datatype);
1208 } else if (context instanceof Resource) {
1210 Layer0 L0 = Layer0.getInstance(graph);
1211 Resource literal = (Resource)context;
1212 Datatype datatype = graph.getRelatedValue(literal, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
1213 return new Validator(datatype);
1217 return new Validator(null);
1223 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1224 public static Object booleanInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1226 return new FunctionImpl1<String, String>() {
1229 public String apply(String input) {
1231 String lower = input.toLowerCase();
1232 if("true".equals(lower) || "false".equals(lower)) return null;
1234 return "Not a valid boolean: " + input;
1242 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Resource")
1243 public static Resource hasStandardResource(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1244 Variable parent = context.getParent(graph);
1245 if(parent instanceof StandardGraphChildVariable) {
1246 StandardGraphChildVariable variable = (StandardGraphChildVariable)parent;
1247 return variable.resource;
1253 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1254 public static Object valueWithoutBinding(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1256 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1258 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1259 Layer0 L0 = Layer0.getInstance(graph);
1260 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel);
1263 if (variable.parentResource == null)
1264 throw new VariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").");
1267 return graph.getRelatedValue2(variable.parentResource, variable.property.predicate, variable);
1268 } catch (NoSingleResultException e) {
1269 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1270 } catch (DoesNotContainValueException e) {
1271 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1276 @SCLValue(type = "ReadGraph -> Variable -> Binding -> a")
1277 public static Object valueWithBinding(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
1279 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1281 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1282 Layer0 L0 = Layer0.getInstance(graph);
1283 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
1286 if (variable.parentResource == null)
1287 throw new VariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").");
1290 return graph.getRelatedValue2(variable.parentResource, variable.property.predicate, variable);
1291 } catch (NoSingleResultException e) {
1292 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1293 } catch (DoesNotContainValueException e) {
1294 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1299 @SCLValue(type = "WriteGraph -> Variable -> a -> Binding -> b")
1300 public static Object valueSetterWithBinding(WriteGraph graph, Variable variable, Object value, Binding binding) throws DatabaseException {
1302 Function4<WriteGraph, Variable, Object, Object, String> modifier = variable.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
1303 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
1304 modifier.apply(graph, variable, value, binding);
1309 static class L0Issue extends StandardIssue {
1311 private final String description;
1313 public L0Issue(String description, Resource type, Resource ... contexts) {
1314 super(type, contexts);
1315 this.description = description;
1319 public Resource write(WriteGraph graph, Resource source) throws DatabaseException {
1320 Layer0 L0 = Layer0.getInstance(graph);
1321 IssueResource IR = IssueResource.getInstance(graph);
1322 Resource issue = super.write(graph, source);
1323 graph.claim(issue, IR.Issue_HasSeverity, IR.Severity_Fatal);
1324 graph.addLiteral(issue, L0.HasDescription, L0.HasDescription_Inverse, description, Bindings.STRING);
1330 private static List<Issue> reportInconsistency(ReadGraph graph, Resource subject, String description, List<Issue> issues) throws DatabaseException {
1331 if(issues == null) issues = new ArrayList<Issue>();
1332 System.err.println("Change set validation reports the following issue: " + NameUtils.getSafeName(graph, subject, true) + ": " + description);
1333 IssueResource IR = IssueResource.getInstance(graph);
1334 issues.add(new L0Issue(description, IR.Issue, subject));
1338 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1339 public static List<Issue> relationValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1341 Layer0 L0 = Layer0.getInstance(graph);
1343 List<Issue> issues = null;
1345 for(Statement stm : graph.getStatements(resource, L0.IsWeaklyRelatedTo)) {
1346 Resource predicate = stm.getPredicate();
1347 Resource object = stm.getObject();
1348 if(!isRelation(graph, L0, predicate)) {
1349 issues = reportInconsistency(graph, resource, "The predicate of a statement must be a relation: " + NameUtils.toString(graph, stm), issues);
1351 if(graph.isInstanceOf(predicate, L0.FunctionalRelation)) {
1352 if(graph.getObjects(resource, predicate).size() > 1)
1353 issues = reportInconsistency(graph, resource,
1355 NameUtils.getSafeName(graph, predicate)
1356 + " is functional.", issues);
1359 Collection<Resource> domain = graph.getObjects(predicate, L0.HasDomain);
1360 if (!isInstanceOfAny(graph, resource, domain, true)) {
1361 StringBuilder sb = new StringBuilder()
1362 .append("The domain of ")
1363 .append(NameUtils.getSafeName(graph, predicate))
1364 .append(" relation is ");
1365 orString(graph, sb, domain).append(".");
1366 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1370 Collection<Resource> range = graph.getObjects(predicate, L0.HasRange);
1371 if (!isInstanceOfAny(graph, object, range, true) && !graph.isInstanceOf(object, L0.SCLValue)) {
1372 StringBuilder sb = new StringBuilder()
1373 .append("The range of ")
1374 .append(NameUtils.getSafeName(graph, predicate))
1375 .append(" relation is ");
1376 orString(graph, sb, range).append(" but current object is ")
1377 .append(NameUtils.getSafeName(graph, object)).append(".");
1378 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1383 return issues != null ? issues : Collections.<Issue>emptyList();
1387 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1388 public static List<Issue> propertyValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1390 List<Issue> issues = null;
1392 Layer0 L0 = Layer0.getInstance(graph);
1393 for(Statement stm : graph.getStatements(resource, L0.HasProperty)) {
1394 Resource subject = stm.getSubject();
1395 Resource predicate = stm.getPredicate();
1396 String error = L0Validations.checkValueType(graph, subject, predicate);
1397 if(error != null) issues = reportInconsistency(graph, subject, error, issues);
1400 return issues != null ? issues : Collections.<Issue>emptyList();
1405 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1406 public static List<Issue> valueValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1408 List<Issue> issues = null;
1410 Layer0 L0 = Layer0.getInstance(graph);
1411 if(graph.hasValue(resource)) {
1412 if(!graph.isInstanceOf(resource, L0.Literal)) {
1413 issues = reportInconsistency(graph, resource,
1414 "Resource has a value but it is not a literal.", issues);
1417 // TODO check that the value is valid for the data type
1421 if(graph.isInstanceOf(resource, L0.Literal)) {
1422 issues = reportInconsistency(graph, resource,
1423 "Resource is a literal but it does not have a value.", issues);
1427 return issues != null ? issues : Collections.<Issue>emptyList();
1432 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1433 public static List<Issue> uriValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1435 List<Issue> issues = null;
1437 Layer0 L0 = Layer0.getInstance(graph);
1438 Resource parent = graph.getPossibleObject(resource, L0.PartOf);
1439 if(parent != null) {
1440 String parentURI = graph.syncRequest(new PossibleURI(parent));
1441 if(parentURI != null) {
1442 String name = graph.getPossibleRelatedValue(resource, L0.HasName);
1444 issues = reportInconsistency(graph, resource, "Resource has a parent with URI but has no valid HasName.", issues);
1449 return issues != null ? issues : Collections.<Issue>emptyList();
1453 private static Resource getPossibleNearestClusterSet(ReadGraph graph, Resource base, Resource resource) throws DatabaseException {
1455 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1456 if(cs.isClusterSet(resource) && !base.equals(resource)) return resource;
1458 Resource nearest = CommonDBUtils.getNearestOwner(graph, Collections.singletonList(resource));
1459 if(nearest == null) return null;
1461 return getPossibleNearestClusterSet(graph, base, nearest);
1465 private static boolean quirks(ReadGraph graph, Resource resource) throws DatabaseException {
1467 if(!resource.isPersistent()) return true;
1468 if(graph.isImmutable(resource)) return true;
1469 if(resource.getResourceId() < 0x2000) return true;
1475 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1476 public static List<Issue> clusterValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1478 if(!Development.DEVELOPMENT) return Collections.<Issue>emptyList();
1480 if(quirks(graph, resource)) return Collections.<Issue>emptyList();
1482 List<Issue> issues = null;
1484 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1485 Resource set = cs.getClusterSetOfCluster(resource);
1487 if(set == null) return reportInconsistency(graph, resource, "Resource cluster is not part of any cluster set", issues);
1489 Resource nearestSet = getPossibleNearestClusterSet(graph, resource, resource);
1490 if(nearestSet == null) {
1491 // This means that there is no owner since RootLibrary is a cluster set
1492 return Collections.<Issue>emptyList();
1495 if(!set.equals(nearestSet)) return reportInconsistency(graph, resource, "The cluster set of a resource is not the nearest owner set", issues);
1497 return Collections.<Issue>emptyList();
1501 private static boolean isInstanceOfAny(ReadGraph graph, Resource r, Collection<Resource> types, boolean ifEmpty) throws DatabaseException {
1502 if (types.isEmpty())
1504 for (Resource type : types) {
1505 if (graph.isInstanceOf(r, type)) {
1512 private static StringBuilder orString(ReadGraph graph, StringBuilder sb, Collection<Resource> rs) throws DatabaseException {
1514 boolean first = true;
1515 for (Resource r : rs) {
1519 sb.append(NameUtils.getSafeName(graph, r));
1525 public static boolean isRelation(ReadGraph g, Layer0 l0, Resource relation) throws DatabaseException {
1526 return g.hasStatement(relation, l0.SubrelationOf) || relation == l0.IsWeaklyRelatedTo;
1529 public static boolean isType(ReadGraph g, Layer0 l0, Resource type) throws DatabaseException {
1530 return g.hasStatement(type, l0.Inherits) || type == l0.Entity;
1533 public static Variable buildChildVariable(ReadGraph graph, Variable context, Resource graphChild, Object nodeChild) throws DatabaseException {
1534 VariableBuilder builder = graph.adapt(graphChild, VariableBuilder.class);
1535 return builder.buildChild(graph, context, build(((AbstractVariable)context).node, nodeChild), graphChild);
1538 private static Variable buildPropertyVariable(ReadGraph graph, Variable variable, Resource parentResource, PropertyInfo graphProperty, Object propertyNode) throws DatabaseException {
1539 VariableNode<?> node = variable instanceof AbstractVariable ? build(((AbstractVariable)variable).node, propertyNode) : null;
1540 return graphProperty.builder.buildProperty(graph, variable, node, parentResource, graphProperty.predicate);
1543 static StandardGraphChildVariable createStandardGraphChildVariable(
1544 AbstractVariable parent, Object child) {
1545 return new StandardGraphChildVariable(parent, build(parent.node, child), null);
1548 private static StandardGraphPropertyVariable createStandardGraphPropertyVariable(
1549 ReadGraph graph, AbstractVariable variable, Object nodeProperty) throws DatabaseException {
1550 Resource propertyResource = getPossiblePropertyResource(graph, variable, nodeProperty);
1551 return new StandardGraphPropertyVariable(graph, variable, build(variable.node, nodeProperty), null, propertyResource);
1554 static Map<String, Variable> ensureVariableMap(
1555 Map<String, Variable> map, int size) {
1556 if(map == null) map = new THashMap<String,Variable>(size);
1560 private static PropertyInfo getPropertyInfo(ReadGraph graph, Resource predicate) throws DatabaseException {
1561 return graph.syncRequest(new PropertyInfoRequest(predicate));
1564 @SuppressWarnings("unchecked")
1565 static String getNodeName(AbstractVariable parent, Object child) {
1566 return parent.node.support.manager.getName(child);
1569 @SuppressWarnings("unchecked")
1570 private static Object getNodeValue(final AbstractVariable variable, final Binding binding) throws NodeManagerException, BindingException {
1571 return variable.node.support.manager.getValue(variable.node.node, binding);
1574 @SuppressWarnings("unchecked")
1575 private static void setNodeValue(final AbstractVariable variable, final Object value, final Binding binding) throws NodeManagerException, BindingException {
1576 variable.node.support.manager.setValue(variable.node.node, value, binding);
1579 @SuppressWarnings("unchecked")
1580 private static String getPossiblePropertyURI(AbstractVariable parent, Object node) {
1581 return parent.node.support.manager.getPropertyURI(parent.node.node, node);