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.procedure.adapter.TransientCacheAsyncListener;
31 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
32 import org.simantics.db.common.request.IsEnumeratedValue;
33 import org.simantics.db.common.request.ObjectsWithType;
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.UnescapedPropertyMapOfResource;
51 import org.simantics.db.layer0.scl.CompileResourceValueRequest;
52 import org.simantics.db.layer0.scl.CompileValueRequest;
53 import org.simantics.db.layer0.util.Layer0Utils;
54 import org.simantics.db.layer0.util.PrimitiveValueParser;
55 import org.simantics.db.layer0.variable.AbstractVariable;
56 import org.simantics.db.layer0.variable.ChildVariableMapRequest;
57 import org.simantics.db.layer0.variable.ExternalSetValue;
58 import org.simantics.db.layer0.variable.PropertyVariableMapRequest;
59 import org.simantics.db.layer0.variable.StandardComposedProperty;
60 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
61 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
62 import org.simantics.db.layer0.variable.SubliteralPropertyVariable;
63 import org.simantics.db.layer0.variable.SubliteralPropertyVariableDeprecated;
64 import org.simantics.db.layer0.variable.ValueAccessor;
65 import org.simantics.db.layer0.variable.Variable;
66 import org.simantics.db.layer0.variable.VariableBuilder;
67 import org.simantics.db.layer0.variable.VariableMap;
68 import org.simantics.db.layer0.variable.VariableMapImpl;
69 import org.simantics.db.layer0.variable.VariableNode;
70 import org.simantics.db.layer0.variable.VariableNodeReadRunnable;
71 import org.simantics.db.layer0.variable.VariableUtils;
72 import org.simantics.db.layer0.variable.Variables;
73 import org.simantics.db.layer0.variable.Variables.NodeStructure;
74 import org.simantics.db.service.ClusteringSupport;
75 import org.simantics.db.service.UndoRedoSupport;
76 import org.simantics.issues.ontology.IssueResource;
77 import org.simantics.layer0.Layer0;
78 import org.simantics.scl.reflection.annotations.SCLValue;
79 import org.simantics.scl.runtime.function.Function4;
80 import org.simantics.scl.runtime.function.FunctionImpl1;
81 import org.simantics.simulator.variable.exceptions.NodeManagerException;
82 import org.simantics.utils.Development;
83 import org.simantics.utils.datastructures.Pair;
84 import org.simantics.utils.strings.StringInputValidator;
86 import gnu.trove.map.hash.THashMap;
87 import gnu.trove.set.hash.THashSet;
91 public static Object standardGetValue1(ReadGraph graph, Variable context) throws DatabaseException {
93 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
96 if(variable.node != null) {
97 Variant value = Variables.requestNodeValue(graph, variable.node);
98 if(Variables.PENDING_NODE_VALUE == value) throw new PendingVariableException("");
99 return value.getValue();
104 if(variable.property.hasEnumerationRange) {
105 Resource object = variable.getRepresents(graph);
106 if(graph.sync(new IsEnumeratedValue(object))) {
107 Layer0 L0 = Layer0.getInstance(graph);
108 if(graph.isInstanceOf(object, L0.Literal)) {
109 return graph.getValue(object);
111 String label = graph.getPossibleRelatedValue2(variable.getRepresents(graph), L0.HasLabel, Bindings.STRING);
112 if(label == null) label = graph.getPossibleRelatedValue(variable.getRepresents(graph), L0.HasName, Bindings.STRING);
113 if(label == null) label = "<no label>";
119 if (variable.isAsserted()) {
120 if (variable.parentResource != null) {
121 Layer0 L0 = Layer0.getInstance(graph);
122 for(Resource assertion : graph.syncRequest(new ObjectsWithType(variable.parentResource, L0.Asserts, L0.Assertion))) {
123 if(variable.property.predicate.equals(graph.getSingleObject(assertion, L0.HasPredicate))) {
124 return graph.getRelatedValue2(assertion, L0.HasObject, variable);
130 return graph.getValue2(variable.getRepresents(graph), variable);
132 } catch (NoSingleResultException e) {
133 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
134 } catch (DoesNotContainValueException e) {
135 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
136 } catch (DatabaseException e) {
137 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
142 public static Object standardGetValue2(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
143 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
146 if(variable.node != null) {
148 Variant value = Variables.requestNodeValue(graph, variable.node, binding);
149 if(Variables.PENDING_NODE_VALUE == value) throw new PendingVariableException("");
150 if(value == null) throw new MissingVariableValueException(variable.getPossibleURI(graph));
151 return value.getValue(binding);
152 } catch (AdaptException e) {
153 throw new DatabaseException(e);
159 Layer0 L0 = Layer0.getInstance(graph);
161 if(variable.property.hasEnumerationRange) {
162 Resource object = variable.getRepresents(graph);
163 if(graph.sync(new IsEnumeratedValue(object))) {
164 if(graph.isInstanceOf(object, L0.Literal)) {
165 return graph.getValue(object);
167 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
172 if (variable.isAsserted()) {
173 if (variable.parentResource != null) {
174 for(Resource assertion : graph.syncRequest(new ObjectsWithType(variable.parentResource, L0.Asserts, L0.Assertion))) {
175 if(variable.property.predicate.equals(graph.getSingleObject(assertion, L0.HasPredicate))) {
176 return graph.getRelatedValue2(assertion, L0.HasObject, context);
182 return graph.getValue2(variable.getRepresents(graph), context, binding);
184 } catch (NoSingleResultException e) {
185 throw new MissingVariableValueException(variable.getPossibleURI(graph));
186 } catch (DoesNotContainValueException e) {
187 throw new MissingVariableValueException(variable.getPossibleURI(graph));
188 } catch (DatabaseException e) {
189 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
194 public static void standardSetValue2(WriteGraph graph, Variable context, final Object value) throws DatabaseException {
196 if(context instanceof StandardGraphPropertyVariable) {
198 final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
201 if(variable.node != null) {
203 final Binding binding = Layer0Utils.getDefaultBinding(graph, variable);
205 final AtomicReference<Object> oldValueRef = new AtomicReference<Object>();
207 variable.node.support.manager.getRealm().syncExec(new Runnable() {
211 oldValueRef.set(getNodeValue(variable, binding));
212 setNodeValue(variable, value, binding);
213 } catch (NodeManagerException e) {
214 throw new RuntimeException(e);
215 } catch (BindingException e) {
216 throw new RuntimeException(e);
220 } catch(RuntimeException e) {
221 if(e.getCause() instanceof NodeManagerException || e.getCause() instanceof BindingException)
222 throw new DatabaseException(e.getCause());
225 } catch (InterruptedException e) {
226 throw new DatabaseException(e);
229 ExternalSetValue ext = new ExternalSetValue(variable.node.support.manager, variable.node.node,
230 oldValueRef.get(), value, binding);
231 graph.getService(UndoRedoSupport.class).addExternalOperation(graph, ext);
238 Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
239 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
241 modifier.apply(graph, context, value, Bindings.getBinding(value.getClass()));
242 } catch (BindingConstructionException e) {
243 throw new DatabaseException(e);
248 public static void standardSetValue3(final WriteGraph graph, Variable context, final Object value, final Binding binding) throws DatabaseException {
251 if(context instanceof StandardGraphPropertyVariable) {
253 final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
256 if(variable.node != null) {
260 variable.node.support.manager.getRealm().syncExec(new Runnable() {
265 Object oldValue = getNodeValue(variable, binding);
266 setNodeValue(variable, value, binding);
267 ExternalSetValue ext = new ExternalSetValue(variable.node.support.manager, variable.node.node, oldValue, value, binding);
268 graph.getService(UndoRedoSupport.class).addExternalOperation(graph, ext);
269 } catch (NodeManagerException | BindingException e) {
270 Logger.defaultLogError(e);
279 } catch (InterruptedException e) {
280 throw new DatabaseException(e);
287 Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
288 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
289 modifier.apply(graph, context, value, binding);
293 public static Datatype getDatatypeFromValue(ReadGraph graph, Variable context) throws DatabaseException {
294 if (context instanceof AbstractVariable) {
295 Binding defaultBinding = ((AbstractVariable)context).getPossibleDefaultBinding(graph);
296 if (defaultBinding != null)
297 return defaultBinding.type();
300 Variant value = context.getVariantValue(graph);
301 if (value.getBinding() == null)
302 throw new DatabaseException("No value binding for " + context.getURI(graph));
304 return value.getBinding().type();
307 @SuppressWarnings("rawtypes")
308 private static class DatatypeGetter implements VariableNodeReadRunnable {
309 final VariableNode node;
313 public DatatypeGetter(VariableNode node) {
317 @SuppressWarnings("unchecked")
321 type = node.support.manager.getDatatype(node.node);
322 } catch (NodeManagerException e) {
327 public String toString() {
328 return "DatatypeGetter(" + node.node + ")";
332 public static Datatype standardGetDatatype(ReadGraph graph, Variable context) throws DatabaseException {
333 if (context instanceof AbstractVariable) {
334 final AbstractVariable variable = (AbstractVariable)context;
335 if (variable.node != null) {
337 DatatypeGetter request = new DatatypeGetter(variable.node);
339 variable.node.support.manager.getRealm().syncExec(request);
341 if (request.exception != null)
342 throw new DatabaseException(request.exception);
345 } catch (InterruptedException e) {
350 return getDatatypeFromValue(graph, context);
353 // @SCLValue(type = "ValueAccessor")
354 // public static ValueAccessor standardValueAccessor = new ValueAccessor() {
357 // public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
358 // return standardGetValue(graph, (StandardGraphPropertyVariable)context);
362 // public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
363 // return standardGetValue(graph, context, binding);
367 // public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
368 // standardSetValue(graph, context, value);
372 // public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
373 // standardSetValue(graph, context, value, binding);
377 // public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
378 // return standardGetDatatype(graph, context);
383 @SCLValue(type = "ValueAccessor")
384 public static ValueAccessor standardValueAccessor = new ValueAccessor() {
387 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
388 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
389 if(accessor != null) return accessor.getValue(graph, context);
391 return standardGetValue1(graph, context);
395 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
396 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
397 if(accessor != null) return accessor.getValue(graph, context, binding);
399 return standardGetValue2(graph, context, binding);
403 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
404 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
405 if(accessor != null) accessor.setValue(graph, context, value);
407 standardSetValue2(graph, context, value);
411 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
412 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
413 if(accessor != null) accessor.setValue(graph, context, value, binding);
415 standardSetValue3(graph, context, value, binding);
419 public Datatype getDatatype(ReadGraph graph, Variable context)
420 throws DatabaseException {
421 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
422 if(accessor != null) return accessor.getDatatype(graph, context);
424 return standardGetDatatype(graph, context);
429 public static Variable getStandardChildDomainPropertyVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
430 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
431 PropertyInfo graphProperty = getPossiblePropertyInfoFromContext(graph, variable, variable.resource, name);
432 return getStandardChildDomainPropertyVariable(graph, context, graphProperty, name);
435 public static Resource getPossiblePropertyResource(ReadGraph graph, AbstractVariable parent, Object node) throws DatabaseException {
436 if(parent != null && parent.node != null && parent.node.node != null && parent.node.support != null) {
437 String propertyURI = getPossiblePropertyURI(parent, node);
438 if(propertyURI != null)
439 return graph.getPossibleResource(propertyURI);
444 public static Variable getStandardChildDomainPropertyVariable(ReadGraph graph, Variable context, PropertyInfo graphProperty, String name) throws DatabaseException {
445 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
446 Object propertyNode = getPossibleNodeProperty(graph, variable, name, true);
447 if(graphProperty != null && graphProperty.builder != null)
448 return buildPropertyVariable(graph, variable, variable.resource, graphProperty, propertyNode);
449 if(propertyNode != null) {
450 // Fallback: try to ask property resource uri from NodeManager
451 return createStandardGraphPropertyVariable(graph, variable, propertyNode);
456 public static Map<String, Variable> getStandardChildDomainPropertyVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
457 // Get properties with null identification
458 return getStandardChildDomainPropertyVariables(graph, context, null, map);
461 public static Map<String, Variable> getStandardChildDomainPropertyVariables(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
463 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
465 Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
466 if(!nodeProperties.isEmpty()) {
468 // Get variables for properties read from the graph
469 Map<String,PropertyInfo> graphProperties = collectPropertyInfosFromContext(graph, variable, variable.resource);
471 Set<String> used = new THashSet<String>(nodeProperties.size());
473 map = ensureVariableMap(map, graphProperties.size() + nodeProperties.size());
475 // Process NodeManager property nodes
476 for(Object nodeProperty : nodeProperties) {
477 String name = getNodeName(variable, nodeProperty);
480 PropertyInfo graphProperty = graphProperties.get(name);
481 if(graphProperty != null && graphProperty.builder != null) {
482 if (classification != null && !graphProperty.hasClassification(classification)) continue;
484 // Combine with identically named graph property
485 map.put(name, buildPropertyVariable(graph, variable, variable.resource, graphProperty, nodeProperty));
489 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
492 // Process graph properties
493 for(PropertyInfo info : graphProperties.values()) {
494 String name = info.name;
495 if(used != null && used.contains(name)) continue;
496 if (classification != null && !info.hasClassification(classification)) continue;
497 if (info.builder != null) {
498 map.put(name, buildPropertyVariable(graph, variable, variable.resource, info, null));
505 if(variable.resource == null) return map;
507 // Only graph properties
508 Collection<Resource> predicates = graph.getPredicates(variable.resource);
509 if(predicates.isEmpty()) return map;
511 map = ensureVariableMap(map, predicates.size());
513 // Process graph properties
514 for(Resource predicate : predicates) {
516 PropertyInfo info = graph.isImmutable(predicate) ?
517 graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
518 graph.syncRequest(new PropertyInfoRequest(predicate));
520 if(!info.isHasProperty) continue;
522 if (classification != null && !info.hasClassification(classification)) continue;
523 if (info.builder != null) {
524 map.put(info.name, buildPropertyVariable(graph, variable, variable.resource, info, null));
535 @SCLValue(type = "VariableMap")
536 public static VariableMap standardChildDomainProperties = new VariableMapImpl() {
539 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
540 return getStandardChildDomainPropertyVariable(graph, context, name);
544 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
545 return getStandardChildDomainPropertyVariables(graph, context, map);
550 public static Variable getStandardPropertyDomainPropertyVariableFromValue(ReadGraph graph, Variable context, String name) throws DatabaseException {
552 if(context instanceof StandardGraphPropertyVariable) {
553 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
554 Resource literal = variable.getPossibleRepresents(graph);
555 Object propertyNode = getPossibleNodeProperty(graph, variable, name, false);
557 if(literal != null) {
558 Variable result = getPossiblePropertyFromContext(graph, variable, literal, name, propertyNode);
559 if(result != null) return result;
562 Variable result = getPossibleSubliteralPropertyFromContext(graph, variable, name);
563 if(result != null) return result;
564 result = getPossiblePropertyFromContext(graph, variable, variable.property.predicate, name, propertyNode);
565 if (result != null) return result;
567 // Get possible property from NodeManager
568 if (propertyNode != null)
569 return createStandardGraphPropertyVariable(graph, variable, propertyNode);
571 } else if (context instanceof StandardGraphChildVariable) {
572 return standardChildDomainProperties.getVariable(graph, context, name);
574 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
579 public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
581 if(context instanceof StandardGraphPropertyVariable) {
582 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
583 map = collectPropertiesFromContext(graph, variable, variable.property.predicate, map);
584 if (variable.parentResource != null) {
585 Resource literal = graph.getPossibleObject(variable.parentResource, variable.property.predicate);
586 if(literal != null) map=collectPropertiesFromContext(graph, variable, literal, map);
587 map=collectSubliteralProperties(graph, variable, map);
590 // Get properties from VariableNode
591 map = getStandardNodePropertyVariables(graph, context, map);
593 } else if (context instanceof StandardGraphChildVariable) {
594 return standardChildDomainProperties.getVariables(graph, context, map);
596 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
601 public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
603 if(context instanceof StandardGraphPropertyVariable) {
604 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
605 map = collectPropertiesFromContext(graph, variable, variable.property.predicate, classification, map);
606 if (variable.parentResource != null) {
607 Resource literal = graph.getPossibleObject(variable.parentResource, variable.property.predicate);
608 if(literal != null) map=collectPropertiesFromContext(graph, variable, literal, classification, map);
611 // Get properties from VariableNode
612 map = getStandardNodePropertyVariables(graph, context, map);
614 } else if (context instanceof StandardGraphChildVariable) {
615 return standardChildDomainProperties.getVariables(graph, context, map);
617 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
622 @SCLValue(type = "VariableMap")
623 public static VariableMap standardPropertyDomainProperties = new VariableMapImpl() {
625 VariableMap getValueVariableMap(ReadGraph graph, Variable context) throws DatabaseException {
626 Resource represents = context.getPossibleRepresents(graph);
627 if(represents == null) return null;
629 VariableMap map = graph.isImmutable(represents) ?
630 graph.syncRequest(new PropertyVariableMapRequest(represents), TransientCacheListener.<VariableMap>instance()) :
631 (VariableMap)graph.getPossibleRelatedValue2(represents, Layer0.getInstance(graph).domainProperties, represents);
633 if(map == standardPropertyDomainProperties) return null;
639 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
640 VariableMap valueMap = getValueVariableMap(graph, context);
641 if(valueMap != null) return valueMap.getVariable(graph, context, name);
642 return getStandardPropertyDomainPropertyVariableFromValue(graph, context, name);
646 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
647 VariableMap valueMap = getValueVariableMap(graph, context);
648 if(valueMap != null) return valueMap.getVariables(graph, context, map);
649 else return getStandardPropertyDomainPropertyVariablesFromValue(graph, context, map);
653 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
654 VariableMap valueMap = getValueVariableMap(graph, context);
655 if(valueMap != null) return valueMap.getVariables(graph, context, classification, map);
656 else return getStandardPropertyDomainPropertyVariablesFromValue(graph, context, classification, map);
661 public static Resource getPossibleGraphChild(ReadGraph graph, Variable variable, String name) throws DatabaseException {
662 Resource resource = variable.getPossibleRepresents(graph);
663 if(resource == null) return null;
664 Map<String, Resource> graphChildren = graph.syncRequest(new UnescapedChildMapOfResource(resource));
665 return graphChildren.get(name);
668 public static Map<String,Resource> getPossibleGraphChildren(ReadGraph graph, Variable variable) throws DatabaseException {
669 Resource resource = variable.getPossibleRepresents(graph);
670 if(resource == null) return Collections.emptyMap();
671 return graph.syncRequest(new UnescapedChildMapOfResource(resource));
674 public static Object getPossibleNodeChild(ReadGraph graph, Variable variable, String name) throws DatabaseException {
675 if (!(variable instanceof AbstractVariable)) return null;
676 VariableNode<?> node = ((AbstractVariable)variable).node;
677 if(node == null) return null;
678 NodeStructure structure = Variables.requestNodeStructure(graph, node);
679 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
680 return structure.children.get(name);
683 public static Collection<Object> getPossibleNodeChildren(ReadGraph graph, Variable variable) throws DatabaseException {
684 if (!(variable instanceof AbstractVariable)) return null;
685 VariableNode<?> node = ((AbstractVariable)variable).node;
686 if(node == null) return Collections.emptyList();
687 NodeStructure structure = Variables.requestNodeStructure(graph, node);
688 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
689 return structure.children.values();
692 public static Object getPossibleNodeProperty(ReadGraph graph, Variable variable, String name, boolean throwPending) throws DatabaseException {
693 if (!(variable instanceof AbstractVariable)) return null;
694 VariableNode<?> node = ((AbstractVariable)variable).node;
695 if(node == null) return null;
696 NodeStructure structure = Variables.requestNodeStructure(graph, node);
697 if(throwPending && Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
698 return structure.properties.get(name);
701 public static Collection<Object> getPossibleNodeProperties(ReadGraph graph, Variable variable) throws DatabaseException {
702 if (!(variable instanceof AbstractVariable)) return null;
703 VariableNode<?> node = ((AbstractVariable)variable).node;
704 if(node == null) return Collections.emptyList();
705 NodeStructure structure = Variables.requestNodeStructure(graph, node);
706 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
707 return structure.properties.values();
710 @SuppressWarnings({ "rawtypes", "unchecked" })
711 public static VariableNode build(VariableNode parent, Object node) {
712 if(node == null) return null;
713 return new VariableNode(parent.support, node);
717 public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
718 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
722 public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, Resource graphChild, String name) throws DatabaseException {
723 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, graphChild, name);
727 public static Map<String, Variable> getStandardChildDomainChildVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
728 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
732 public static Map<String, Variable> getStandardChildDomainChildVariables(ReadGraph graph, Variable context, Map<String,Resource> graphChildren, Map<String, Variable> map) throws DatabaseException {
733 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, graphChildren, map);
737 * Get a map of child Variables from a node manager-based Variable, combined with the existing variables in #map.
738 * @param graph The read graph.
739 * @param context The parent Variable.
740 * @param map A map of variables into which the new variables are merged.
741 * @return A map from variable names to instances
742 * @throws DatabaseException
744 public static Map<String, Variable> getStandardNodeChildVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
745 AbstractVariable variable = (AbstractVariable)context;
746 if (variable.node == null) return map;
748 Collection<Object> nodeChildren = getPossibleNodeChildren(graph, variable);
749 if (nodeChildren.isEmpty()) return map;
751 map = ensureVariableMap(map, nodeChildren.size());
753 for(Object nodeChild : nodeChildren) {
754 String name = getNodeName(variable, nodeChild);
755 if (!map.containsKey(name))
756 map.put(name, createStandardGraphChildVariable(variable, nodeChild));
763 * Get a map of property Variables from a node manager-based Variable, combined with the existing variables in #map.
764 * @param graph The read graph.
765 * @param context The parent Variable.
766 * @param map A map of variables into which the new variables are merged.
767 * @return A map from variable names to instances
768 * @throws DatabaseException
770 public static Map<String, Variable> getStandardNodePropertyVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
771 AbstractVariable variable = (AbstractVariable)context;
772 if (variable.node == null) return map;
774 Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
775 if (nodeProperties.isEmpty()) return map;
777 map = ensureVariableMap(map, nodeProperties.size());
779 for(Object nodeProperty : nodeProperties) {
780 String name = getNodeName(variable, nodeProperty);
781 if (!map.containsKey(name)) {
782 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
789 @SCLValue(type = "VariableMap")
790 public static VariableMap standardChildDomainChildren = new VariableMapImpl() {
793 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
794 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
798 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
799 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
804 @SCLValue(type = "VariableMap")
805 public static VariableMap standardPropertyDomainChildren = new VariableMapImpl() {
808 * Get a possible non-standard VariableMap defined in the graph.
809 * @param graph The graph
810 * @param context The context node
811 * @return A non-standard VariableMap instance for the context node,
812 * or null, if not defined or defined as this instance.
813 * @throws DatabaseException
815 VariableMap getValueVariableMap(ReadGraph graph, Variable context) throws DatabaseException {
816 Resource represents = context.getPossibleRepresents(graph);
817 if(represents == null) return null;
818 VariableMap map = graph.syncRequest(new ChildVariableMapRequest(represents));
819 if(map == standardPropertyDomainChildren) return null;
824 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
825 // Delegate call to a non-standard variable map?
826 VariableMap valueMap = getValueVariableMap(graph, context);
827 if(valueMap != null) return valueMap.getVariable(graph, context, name);
829 if(context instanceof StandardGraphPropertyVariable) {
830 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
831 Datatype dt = variable.getDatatype(graph);
832 if (dt instanceof ArrayType) {
833 ChildReference ref = getPossibleIndexReference(name);
835 return new SubliteralPropertyVariableDeprecated(variable, ref);
838 // Check for a child node provided by the NodeManager
839 if (variable.node != null) {
840 Object childNode = getPossibleNodeChild(graph, variable, name);
841 if (childNode != null)
842 return createStandardGraphChildVariable(variable, childNode);
844 return standardChildDomainChildren.getVariable(graph, context, name);
845 } else if (context instanceof StandardGraphChildVariable) {
846 return standardChildDomainChildren.getVariable(graph, context, name);
848 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
853 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
854 // Delegate call to a non-standard variable map?
855 VariableMap valueMap = getValueVariableMap(graph, context);
856 if(valueMap != null) return valueMap.getVariables(graph, context, map);
858 if(context instanceof StandardGraphPropertyVariable) {
859 // Get child variables provided by the NodeManager
860 Map<String, Variable> result = getStandardNodeChildVariables(graph, context, map);
861 return standardChildDomainChildren.getVariables(graph, context, result);
862 } else if (context instanceof StandardGraphChildVariable) {
863 return standardChildDomainChildren.getVariables(graph, context, map);
865 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
871 protected static ChildReference getPossibleIndexReference(String name) {
872 if (name.startsWith("i-")) {
874 int index = Integer.parseInt(name.substring(2));
875 return new IndexReference(index);
876 } catch (NumberFormatException e) {}
881 protected static ValueAccessor getPossiblePropertyValueAccessor(ReadGraph graph, StandardGraphPropertyVariable variable) throws DatabaseException {
882 if(variable.property == null) return null;
883 return variable.property.valueAccessor;
884 // return graph.syncRequest(new PropertyValueAccessorRequest(variable.property), TransientCacheAsyncListener.<ValueAccessor>instance());
885 // return graph.syncRequest(new PossibleRelatedValueImplied2<ValueAccessor>(variable.property, Layer0.getInstance(graph).valueAccessor));
888 public static ValueAccessor getPossibleValueValueAccessor(ReadGraph graph, Variable variable) throws DatabaseException {
889 Resource value = variable.getPossibleRepresents(graph);
890 if(value == null) return null;
891 //return graph.syncRequest(new PropertyValueAccessorRequest(value));
892 return graph.syncRequest(new PossibleRelatedValueImplied2<ValueAccessor>(value, Layer0.getInstance(graph).valueAccessor));
895 public static PropertyInfo getPossiblePropertyInfoFromContext(ReadGraph graph, Variable variable, Resource context, String name) throws DatabaseException {
896 if(context == null) return null;
897 Map<String, PropertyInfo> predicates = graph.syncRequest(new UnescapedPropertyMapOfResource(context));
898 return predicates.get(name);
901 public static Variable getPossiblePropertyFromContext(ReadGraph graph, Variable variable, Resource context, String name, Object propertyNode) throws DatabaseException {
902 PropertyInfo info = getPossiblePropertyInfoFromContext(graph, variable, context, name);
903 if(info == null || info.builder == null) return null;
904 return buildPropertyVariable(graph, variable, context, info, propertyNode);
907 public static Variable getPossibleSubliteralPropertyFromContext(ReadGraph graph, StandardGraphPropertyVariable variable, String name) throws DatabaseException {
909 Resource predicate = variable.property.predicate;
910 if(predicate == null) return null;
912 PropertyInfo info = getPropertyInfo(graph, predicate);
913 Pair<Resource, ChildReference> p = info.subliteralPredicates.get(name);
914 if(p == null) return null;
916 return new SubliteralPropertyVariable(graph, variable, p.first, p.second);
920 public static Map<String, PropertyInfo> collectPropertyInfosFromContext(ReadGraph graph, Variable variable, Resource context) throws DatabaseException {
921 if(context == null) return Collections.emptyMap();
922 return graph.isImmutable(context) ?
923 graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance()) :
924 graph.syncRequest(new UnescapedPropertyMapOfResource(context));
927 public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, Map<String, Variable> map) throws DatabaseException {
929 Map<String,PropertyInfo> properties = graph.isImmutable(context) ?
930 graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance()) :
931 graph.syncRequest(new UnescapedPropertyMapOfResource(context));
933 if(properties.isEmpty()) return map;
935 map = ensureVariableMap(map, properties.size());
937 for(PropertyInfo info : properties.values()) {
938 String name = info.name;
939 if (info.builder != null) {
940 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
949 public static Map<String, Variable> collectSubliteralProperties(ReadGraph graph, StandardGraphPropertyVariable variable, Map<String, Variable> map) throws DatabaseException {
951 Resource predicate = variable.property.predicate;
952 if(predicate == null) return map;
954 PropertyInfo info = getPropertyInfo(graph, predicate);
955 if(info.subliteralPredicates.isEmpty()) return map;
957 map = ensureVariableMap(map, info.subliteralPredicates.size());
959 for(Map.Entry<String, Pair<Resource, ChildReference>> entry : info.subliteralPredicates.entrySet()) {
960 String key = entry.getKey();
961 Pair<Resource, ChildReference> p = entry.getValue();
962 if(map == null) map = new THashMap<String,Variable>();
963 map.put(key, new SubliteralPropertyVariable(graph, variable, p.first, p.second));
970 public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, String classification, Map<String, Variable> map) throws DatabaseException {
972 if(graph.isImmutable(context)) {
974 Map<String,PropertyInfo> properties = graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance());
975 for(PropertyInfo info : properties.values()) {
977 if(info.classifications.contains(classification) && info.builder != null) {
978 String name = info.name;
979 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
980 if(map == null) map = new THashMap<String,Variable>();
988 Collection<Resource> predicates = graph.getPredicates(context);
990 if(predicates.isEmpty()) return map;
992 map = ensureVariableMap(map, predicates.size());
994 for(Resource predicate : predicates) {
996 PropertyInfo info = graph.isImmutable(predicate) ?
997 graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
998 graph.syncRequest(new PropertyInfoRequest(predicate));
1000 if(!info.isHasProperty) continue;
1002 if(info.classifications.contains(classification) && info.builder != null) {
1003 String name = info.name;
1004 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1005 if(map == null) map = new THashMap<String,Variable>();
1017 @SCLValue(type = "ReadGraph -> Resource -> a -> String")
1018 public static String entityLabel(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1019 if(context instanceof Resource) {
1020 return NameUtils.getSafeLabel(graph, ((Resource)context));
1021 } else if (context instanceof Variable) {
1022 Variable parent = ((Variable)context).getParent(graph);
1023 Resource represents = parent.getRepresents(graph);
1024 return NameUtils.getSafeLabel(graph, represents);
1026 throw new DatabaseException("Unknown context " + context);
1030 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1031 public static Object listResources(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1032 return ListUtils.toList(graph, resource);
1035 @SCLValue(type = "ReadGraph -> Resource -> Variable -> [String]")
1036 public static List<String> standardClassifications(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1037 ArrayList<String> result = new ArrayList<String>();
1038 Resource predicate = context.getParent(graph).getPossiblePredicateResource(graph);
1039 if(predicate != null) {
1040 for(Resource type : graph.getTypes(predicate)) {
1041 String uri = graph.getPossibleURI(type);
1042 if(uri != null) result.add(uri);
1048 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1049 public static Boolean standardValidValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1050 return Boolean.TRUE;
1053 @SCLValue(type = "ReadGraph -> Resource -> a -> StringInputValidator")
1054 public static StringInputValidator standardValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1055 return StringInputValidator.PASS;
1058 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1059 public static Boolean standardRequiredValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1060 return Boolean.FALSE;
1063 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Boolean")
1064 public static Boolean standardDefaultValue(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1065 Variable property = context.getParent(graph);
1066 if(property instanceof StandardGraphPropertyVariable) {
1067 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)property;
1068 if (variable.parentResource != null) {
1069 Statement stm = graph.getPossibleStatement(variable.parentResource, variable.property.predicate);
1070 return stm != null && stm.isAsserted(variable.parentResource);
1073 return Boolean.FALSE;
1076 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1077 public static Boolean standardReadOnlyValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1078 return Boolean.FALSE;
1081 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1082 public static Object resourceAsValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1086 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1087 public static Object functionApplication(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1088 return Functions.exec(graph, resource, graph, resource, context);
1091 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1092 public static Object computeExpression(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1093 if(context instanceof Variable) {
1094 return CompileValueRequest.compileAndEvaluate(graph, (Variable)context);
1095 } if (context instanceof Resource) {
1096 return CompileResourceValueRequest.compileAndEvaluate(graph, (Resource)converter);
1098 throw new IllegalStateException("Unknown context " + context);
1102 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1103 public static Object composedPropertyValue(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1104 if(context instanceof Variable) {
1105 return new StandardComposedProperty();
1106 } if (context instanceof Resource) {
1107 return new StandardComposedProperty();
1109 throw new IllegalStateException("Unknown context " + context);
1113 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1114 public static Object numberInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1116 class Validator extends FunctionImpl1<String, String> {
1118 private final Datatype datatype;
1120 public Validator(Datatype datatype) {
1121 this.datatype = datatype;
1125 public String apply(String input) {
1127 if(datatype == null) return null;
1131 if(datatype instanceof NumberType) {
1133 Number number = (Number)PrimitiveValueParser.parse(input, datatype);
1134 NumberType nt = (NumberType)datatype;
1135 Range r = nt.getRange();
1137 if(!r.contains(number)) return "Value is out of valid range";
1142 } catch (NumberFormatException e) {
1143 return "Not a valid floating-point number";
1144 } catch (IllegalArgumentException e) {
1145 return "Not a valid floating-point number";
1152 if(context instanceof Variable) {
1154 Variable variable = (Variable)context;
1155 Variable property = variable.getParent(graph);
1156 Datatype datatype = property.getPossibleDatatype(graph);
1157 return new Validator(datatype);
1159 } else if (context instanceof Resource) {
1161 Layer0 L0 = Layer0.getInstance(graph);
1162 Resource literal = (Resource)context;
1163 Datatype datatype = graph.getRelatedValue(literal, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
1164 return new Validator(datatype);
1168 return new Validator(null);
1174 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1175 public static Object booleanInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1177 return new FunctionImpl1<String, String>() {
1180 public String apply(String input) {
1182 String lower = input.toLowerCase();
1183 if("true".equals(lower) || "false".equals(lower)) return null;
1185 return "Not a valid boolean: " + input;
1193 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Resource")
1194 public static Resource hasStandardResource(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1195 Variable parent = context.getParent(graph);
1196 if(parent instanceof StandardGraphChildVariable) {
1197 StandardGraphChildVariable variable = (StandardGraphChildVariable)parent;
1198 return variable.resource;
1204 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1205 public static Object valueWithoutBinding(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1207 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1209 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1210 Layer0 L0 = Layer0.getInstance(graph);
1211 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel);
1214 if (variable.parentResource == null)
1215 throw new VariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").");
1218 return graph.getRelatedValue2(variable.parentResource, variable.property.predicate, variable);
1219 } catch (NoSingleResultException e) {
1220 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1221 } catch (DoesNotContainValueException e) {
1222 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1227 @SCLValue(type = "ReadGraph -> Variable -> Binding -> a")
1228 public static Object valueWithBinding(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
1230 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1232 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1233 Layer0 L0 = Layer0.getInstance(graph);
1234 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
1237 if (variable.parentResource == null)
1238 throw new VariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").");
1241 return graph.getRelatedValue2(variable.parentResource, variable.property.predicate, variable);
1242 } catch (NoSingleResultException e) {
1243 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1244 } catch (DoesNotContainValueException e) {
1245 throw new MissingVariableValueException(variable.getPossibleURI(graph));
1250 @SCLValue(type = "WriteGraph -> Variable -> a -> Binding -> b")
1251 public static Object valueSetterWithBinding(WriteGraph graph, Variable variable, Object value, Binding binding) throws DatabaseException {
1253 Function4<WriteGraph, Variable, Object, Object, String> modifier = variable.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
1254 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
1255 modifier.apply(graph, variable, value, binding);
1260 static class L0Issue extends StandardIssue {
1262 private final String description;
1264 public L0Issue(String description, Resource type, Resource ... contexts) {
1265 super(type, contexts);
1266 this.description = description;
1270 public Resource write(WriteGraph graph, Resource source) throws DatabaseException {
1271 Layer0 L0 = Layer0.getInstance(graph);
1272 IssueResource IR = IssueResource.getInstance(graph);
1273 Resource issue = super.write(graph, source);
1274 graph.claim(issue, IR.Issue_HasSeverity, IR.Severity_Fatal);
1275 graph.addLiteral(issue, L0.HasDescription, L0.HasDescription_Inverse, description, Bindings.STRING);
1281 private static List<Issue> reportInconsistency(ReadGraph graph, Resource subject, String description, List<Issue> issues) throws DatabaseException {
1282 if(issues == null) issues = new ArrayList<Issue>();
1283 System.err.println("Change set validation reports the following issue: " + NameUtils.getSafeName(graph, subject, true) + ": " + description);
1284 IssueResource IR = IssueResource.getInstance(graph);
1285 issues.add(new L0Issue(description, IR.Issue, subject));
1289 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1290 public static List<Issue> relationValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1292 Layer0 L0 = Layer0.getInstance(graph);
1294 List<Issue> issues = null;
1296 for(Statement stm : graph.getStatements(resource, L0.IsWeaklyRelatedTo)) {
1297 Resource predicate = stm.getPredicate();
1298 Resource object = stm.getObject();
1299 if(!isRelation(graph, L0, predicate)) {
1300 issues = reportInconsistency(graph, resource, "The predicate of a statement must be a relation: " + NameUtils.toString(graph, stm), issues);
1302 if(graph.isInstanceOf(predicate, L0.FunctionalRelation)) {
1303 if(graph.getObjects(resource, predicate).size() > 1)
1304 issues = reportInconsistency(graph, resource,
1306 NameUtils.getSafeName(graph, predicate)
1307 + " is functional.", issues);
1310 Collection<Resource> domain = graph.getObjects(predicate, L0.HasDomain);
1311 if (!isInstanceOfAny(graph, resource, domain, true)) {
1312 StringBuilder sb = new StringBuilder()
1313 .append("The domain of ")
1314 .append(NameUtils.getSafeName(graph, predicate))
1315 .append(" relation is ");
1316 orString(graph, sb, domain).append(".");
1317 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1321 Collection<Resource> range = graph.getObjects(predicate, L0.HasRange);
1322 if (!isInstanceOfAny(graph, object, range, true) && !graph.isInstanceOf(object, L0.SCLValue)) {
1323 StringBuilder sb = new StringBuilder()
1324 .append("The range of ")
1325 .append(NameUtils.getSafeName(graph, predicate))
1326 .append(" relation is ");
1327 orString(graph, sb, range).append(" but current object is ")
1328 .append(NameUtils.getSafeName(graph, object)).append(".");
1329 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1334 return issues != null ? issues : Collections.<Issue>emptyList();
1338 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1339 public static List<Issue> propertyValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1341 List<Issue> issues = null;
1343 Layer0 L0 = Layer0.getInstance(graph);
1344 for(Statement stm : graph.getStatements(resource, L0.HasProperty)) {
1345 Resource subject = stm.getSubject();
1346 Resource predicate = stm.getPredicate();
1347 String error = L0Validations.checkValueType(graph, subject, predicate);
1348 if(error != null) issues = reportInconsistency(graph, subject, error, issues);
1351 return issues != null ? issues : Collections.<Issue>emptyList();
1356 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1357 public static List<Issue> valueValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1359 List<Issue> issues = null;
1361 Layer0 L0 = Layer0.getInstance(graph);
1362 if(graph.hasValue(resource)) {
1363 if(!graph.isInstanceOf(resource, L0.Literal)) {
1364 issues = reportInconsistency(graph, resource,
1365 "Resource has a value but it is not a literal.", issues);
1368 // TODO check that the value is valid for the data type
1372 if(graph.isInstanceOf(resource, L0.Literal)) {
1373 issues = reportInconsistency(graph, resource,
1374 "Resource is a literal but it does not have a value.", issues);
1378 return issues != null ? issues : Collections.<Issue>emptyList();
1383 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1384 public static List<Issue> uriValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1386 List<Issue> issues = null;
1388 Layer0 L0 = Layer0.getInstance(graph);
1389 Resource parent = graph.getPossibleObject(resource, L0.PartOf);
1390 if(parent != null) {
1391 String parentURI = graph.syncRequest(new PossibleURI(parent));
1392 if(parentURI != null) {
1393 String name = graph.getPossibleRelatedValue(resource, L0.HasName);
1395 issues = reportInconsistency(graph, resource, "Resource has a parent with URI but has no valid HasName.", issues);
1400 return issues != null ? issues : Collections.<Issue>emptyList();
1404 private static Resource getPossibleNearestClusterSet(ReadGraph graph, Resource base, Resource resource) throws DatabaseException {
1406 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1407 if(cs.isClusterSet(resource) && !base.equals(resource)) return resource;
1409 Resource nearest = CommonDBUtils.getNearestOwner(graph, Collections.singletonList(resource));
1410 if(nearest == null) return null;
1412 return getPossibleNearestClusterSet(graph, base, nearest);
1416 private static boolean quirks(ReadGraph graph, Resource resource) throws DatabaseException {
1418 if(!resource.isPersistent()) return true;
1419 if(graph.isImmutable(resource)) return true;
1420 if(resource.getResourceId() < 0x2000) return true;
1426 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1427 public static List<Issue> clusterValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1429 if(!Development.DEVELOPMENT) return Collections.<Issue>emptyList();
1431 if(quirks(graph, resource)) return Collections.<Issue>emptyList();
1433 List<Issue> issues = null;
1435 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1436 Resource set = cs.getClusterSetOfCluster(resource);
1438 if(set == null) return reportInconsistency(graph, resource, "Resource cluster is not part of any cluster set", issues);
1440 Resource nearestSet = getPossibleNearestClusterSet(graph, resource, resource);
1441 if(nearestSet == null) {
1442 // This means that there is no owner since RootLibrary is a cluster set
1443 return Collections.<Issue>emptyList();
1446 if(!set.equals(nearestSet)) return reportInconsistency(graph, resource, "The cluster set of a resource is not the nearest owner set", issues);
1448 return Collections.<Issue>emptyList();
1452 private static boolean isInstanceOfAny(ReadGraph graph, Resource r, Collection<Resource> types, boolean ifEmpty) throws DatabaseException {
1453 if (types.isEmpty())
1455 for (Resource type : types) {
1456 if (graph.isInstanceOf(r, type)) {
1463 private static StringBuilder orString(ReadGraph graph, StringBuilder sb, Collection<Resource> rs) throws DatabaseException {
1465 boolean first = true;
1466 for (Resource r : rs) {
1470 sb.append(NameUtils.getSafeName(graph, r));
1476 public static boolean isRelation(ReadGraph g, Layer0 l0, Resource relation) throws DatabaseException {
1477 return g.hasStatement(relation, l0.SubrelationOf) || relation == l0.IsWeaklyRelatedTo;
1480 public static boolean isType(ReadGraph g, Layer0 l0, Resource type) throws DatabaseException {
1481 return g.hasStatement(type, l0.Inherits) || type == l0.Entity;
1484 public static Variable buildChildVariable(ReadGraph graph, Variable context, Resource graphChild, Object nodeChild) throws DatabaseException {
1485 VariableBuilder builder = graph.adapt(graphChild, VariableBuilder.class);
1486 return builder.buildChild(graph, context, build(((AbstractVariable)context).node, nodeChild), graphChild);
1489 private static Variable buildPropertyVariable(ReadGraph graph, Variable variable, Resource parentResource, PropertyInfo graphProperty, Object propertyNode) throws DatabaseException {
1490 VariableNode<?> node = variable instanceof AbstractVariable ? build(((AbstractVariable)variable).node, propertyNode) : null;
1491 return graphProperty.builder.buildProperty(graph, variable, node, parentResource, graphProperty.predicate);
1494 static StandardGraphChildVariable createStandardGraphChildVariable(
1495 AbstractVariable parent, Object child) {
1496 return new StandardGraphChildVariable(parent, build(parent.node, child), null);
1499 private static StandardGraphPropertyVariable createStandardGraphPropertyVariable(
1500 ReadGraph graph, AbstractVariable variable, Object nodeProperty) throws DatabaseException {
1501 Resource propertyResource = getPossiblePropertyResource(graph, variable, nodeProperty);
1502 return new StandardGraphPropertyVariable(graph, variable, build(variable.node, nodeProperty), null, propertyResource);
1505 static Map<String, Variable> ensureVariableMap(
1506 Map<String, Variable> map, int size) {
1507 if(map == null) map = new THashMap<String,Variable>(size);
1511 private static PropertyInfo getPropertyInfo(ReadGraph graph, Resource predicate) throws DatabaseException {
1512 return graph.syncRequest(new PropertyInfoRequest(predicate));
1515 @SuppressWarnings("unchecked")
1516 static String getNodeName(AbstractVariable parent, Object child) {
1517 return parent.node.support.manager.getName(child);
1520 @SuppressWarnings("unchecked")
1521 private static Object getNodeValue(final AbstractVariable variable, final Binding binding) throws NodeManagerException, BindingException {
1522 return variable.node.support.manager.getValue(variable.node.node, binding);
1525 @SuppressWarnings("unchecked")
1526 private static void setNodeValue(final AbstractVariable variable, final Object value, final Binding binding) throws NodeManagerException, BindingException {
1527 variable.node.support.manager.setValue(variable.node.node, value, binding);
1530 @SuppressWarnings("unchecked")
1531 private static String getPossiblePropertyURI(AbstractVariable parent, Object node) {
1532 return parent.node.support.manager.getPropertyURI(parent.node.node, node);