1 package org.simantics.db.layer0.function;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.HashMap;
10 import java.util.concurrent.atomic.AtomicReference;
12 import org.simantics.databoard.Bindings;
13 import org.simantics.databoard.accessor.reference.ChildReference;
14 import org.simantics.databoard.accessor.reference.IndexReference;
15 import org.simantics.databoard.adapter.AdaptException;
16 import org.simantics.databoard.binding.Binding;
17 import org.simantics.databoard.binding.error.BindingConstructionException;
18 import org.simantics.databoard.binding.error.BindingException;
19 import org.simantics.databoard.binding.mutable.Variant;
20 import org.simantics.databoard.type.ArrayType;
21 import org.simantics.databoard.type.Datatype;
22 import org.simantics.databoard.type.NumberType;
23 import org.simantics.databoard.util.Range;
24 import org.simantics.db.Issue;
25 import org.simantics.db.ReadGraph;
26 import org.simantics.db.Resource;
27 import org.simantics.db.Statement;
28 import org.simantics.db.WriteGraph;
29 import org.simantics.db.common.issue.StandardIssue;
30 import org.simantics.db.common.primitiverequest.PossibleRelatedValueImplied2;
31 import org.simantics.db.common.primitiverequest.PossibleResource;
32 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
33 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
34 import org.simantics.db.common.request.IsEnumeratedValue;
35 import org.simantics.db.common.uri.UnescapedChildMapOfResource;
36 import org.simantics.db.common.utils.CommonDBUtils;
37 import org.simantics.db.common.utils.Functions;
38 import org.simantics.db.common.utils.ListUtils;
39 import org.simantics.db.common.utils.NameUtils;
40 import org.simantics.db.common.utils.NearestOwnerFinder;
41 import org.simantics.db.common.validation.L0Validations;
42 import org.simantics.db.exception.AdaptionException;
43 import org.simantics.db.exception.DatabaseException;
44 import org.simantics.db.exception.DoesNotContainValueException;
45 import org.simantics.db.exception.NoSingleResultException;
46 import org.simantics.db.exception.RuntimeDatabaseException;
47 import org.simantics.db.layer0.exception.InvalidVariableException;
48 import org.simantics.db.layer0.exception.MissingVariableException;
49 import org.simantics.db.layer0.exception.MissingVariableValueException;
50 import org.simantics.db.layer0.exception.PendingVariableException;
51 import org.simantics.db.layer0.request.PossibleURI;
52 import org.simantics.db.layer0.request.PropertyInfo;
53 import org.simantics.db.layer0.request.PropertyInfoRequest;
54 import org.simantics.db.layer0.request.UnescapedAssertedPropertyMapOfResource;
55 import org.simantics.db.layer0.request.UnescapedMethodMapOfResource;
56 import org.simantics.db.layer0.request.UnescapedPropertyMapOfResource;
57 import org.simantics.db.layer0.scl.CompileResourceValueRequest;
58 import org.simantics.db.layer0.scl.CompileValueRequest;
59 import org.simantics.db.layer0.util.Layer0Utils;
60 import org.simantics.db.layer0.util.PrimitiveValueParser;
61 import org.simantics.db.layer0.variable.AbstractVariable;
62 import org.simantics.db.layer0.variable.ChildVariableMapRequest;
63 import org.simantics.db.layer0.variable.ExternalSetValue;
64 import org.simantics.db.layer0.variable.PropertyVariableMapRequest;
65 import org.simantics.db.layer0.variable.StandardAssertedGraphPropertyVariable;
66 import org.simantics.db.layer0.variable.StandardComposedProperty;
67 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
68 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
69 import org.simantics.db.layer0.variable.SubliteralPropertyVariable;
70 import org.simantics.db.layer0.variable.SubliteralPropertyVariableDeprecated;
71 import org.simantics.db.layer0.variable.ValueAccessor;
72 import org.simantics.db.layer0.variable.Variable;
73 import org.simantics.db.layer0.variable.VariableBuilder;
74 import org.simantics.db.layer0.variable.VariableMap;
75 import org.simantics.db.layer0.variable.VariableMapImpl;
76 import org.simantics.db.layer0.variable.VariableNode;
77 import org.simantics.db.layer0.variable.VariableNodeReadRunnable;
78 import org.simantics.db.layer0.variable.VariableUtils;
79 import org.simantics.db.layer0.variable.Variables;
80 import org.simantics.db.layer0.variable.Variables.NodeStructure;
81 import org.simantics.db.service.ClusteringSupport;
82 import org.simantics.db.service.UndoRedoSupport;
83 import org.simantics.issues.ontology.IssueResource;
84 import org.simantics.layer0.Layer0;
85 import org.simantics.scl.reflection.annotations.SCLValue;
86 import org.simantics.scl.runtime.SCLContext;
87 import org.simantics.scl.runtime.function.Function4;
88 import org.simantics.scl.runtime.function.FunctionImpl1;
89 import org.simantics.scl.runtime.function.FunctionImpl2;
90 import org.simantics.simulator.variable.exceptions.NodeManagerException;
91 import org.simantics.utils.Development;
92 import org.simantics.utils.datastructures.Pair;
93 import org.simantics.utils.strings.StringInputValidator;
94 import org.slf4j.Logger;
95 import org.slf4j.LoggerFactory;
97 import gnu.trove.map.hash.THashMap;
98 import gnu.trove.set.hash.THashSet;
102 private static final Logger LOGGER = LoggerFactory.getLogger(All.class);
104 public static Object standardGetValue1(ReadGraph graph, Variable context) throws DatabaseException {
106 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
109 if(variable.node != null) {
110 Variant value = Variables.requestNodeValue(graph, variable.node);
111 if(Variables.PENDING_NODE_VALUE == value) throw new PendingVariableException("");
112 return value.getValue();
117 if(variable.property.hasEnumerationRange) {
118 Resource object = variable.getRepresents(graph);
119 if(graph.sync(new IsEnumeratedValue(object))) {
120 Layer0 L0 = Layer0.getInstance(graph);
121 if(graph.isInstanceOf(object, L0.Literal)) {
122 return graph.getValue(object);
124 String label = graph.getPossibleRelatedValue2(variable.getRepresents(graph), L0.HasLabel, Bindings.STRING);
125 if(label == null) label = graph.getPossibleRelatedValue(variable.getRepresents(graph), L0.HasName, Bindings.STRING);
126 if(label == null) label = "<no label>";
132 if (variable.isAsserted()) {
133 if (variable.parentResource != null) {
134 Map<String, Pair<PropertyInfo, Resource>> assertions = graph.syncRequest(
135 new UnescapedAssertedPropertyMapOfResource(variable.parentResource),
136 TransientCacheAsyncListener.instance());
138 // NOTE: This optimization assumes the property
139 // variable's representation is the asserted object.
140 Resource object = variable.getPossibleRepresents(graph);
141 if (object != null) {
142 return graph.getValue2(object, variable);
144 for (Pair<PropertyInfo, Resource> assertion : assertions.values()) {
145 if (assertion.first.predicate.equals(variable.getPossiblePredicateResource(graph))) {
146 return graph.getValue2(assertion.second, variable);
153 return graph.getValue2(variable.getRepresents(graph), variable);
155 } catch (PendingVariableException e) {
157 } catch (NoSingleResultException e) {
158 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
159 } catch (DoesNotContainValueException e) {
160 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
161 } catch (DatabaseException e) {
162 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
167 public static Object standardGetValue2(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
168 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
171 if(variable.node != null) {
173 Variant value = Variables.requestNodeValue(graph, variable.node, binding);
174 if(Variables.PENDING_NODE_VALUE == value) throw new PendingVariableException("");
175 if(value == null) throw new MissingVariableValueException(variable.getPossibleURI(graph));
176 return value.getValue(binding);
177 } catch (AdaptException e) {
178 throw new AdaptionException("Could not get value for " + context.getURI(graph), e);
184 if(variable.property.hasEnumerationRange) {
185 Resource object = variable.getRepresents(graph);
186 if(graph.sync(new IsEnumeratedValue(object))) {
187 Layer0 L0 = Layer0.getInstance(graph);
188 if(graph.isInstanceOf(object, L0.Literal)) {
189 return graph.getValue(object, binding);
191 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
196 if (variable.isAsserted()) {
197 if (variable.parentResource != null) {
198 Map<String, Pair<PropertyInfo, Resource>> assertions = graph.syncRequest(
199 new UnescapedAssertedPropertyMapOfResource(variable.parentResource),
200 TransientCacheAsyncListener.instance());
202 // NOTE: This optimization assumes the property
203 // variable's representation is the asserted object.
204 Resource object = variable.getPossibleRepresents(graph);
205 if (object != null) {
206 return graph.getValue2(object, variable, binding);
208 for (Pair<PropertyInfo, Resource> assertion : assertions.values()) {
209 if (assertion.first.predicate.equals(variable.getPossiblePredicateResource(graph))) {
210 return graph.getValue2(assertion.second, variable, binding);
217 return graph.getValue2(variable.getRepresents(graph), context, binding);
219 } catch (NoSingleResultException e) {
220 throw new MissingVariableValueException(variable.getPossibleURI(graph));
221 } catch (DoesNotContainValueException e) {
222 throw new MissingVariableValueException(variable.getPossibleURI(graph));
223 } catch (DatabaseException e) {
224 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
229 public static void standardSetValue2(WriteGraph graph, Variable context, final Object value) throws DatabaseException {
231 if(context instanceof StandardGraphPropertyVariable) {
233 final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
236 if(variable.node != null) {
238 final Binding binding = Layer0Utils.getDefaultBinding(graph, variable);
240 final AtomicReference<Object> oldValueRef = new AtomicReference<Object>();
242 variable.node.support.manager.getRealm().syncExec(new Runnable() {
246 oldValueRef.set(getNodeValue(variable, binding));
247 setNodeValue(variable, value, binding);
248 } catch (NodeManagerException e) {
249 throw new RuntimeException(e);
250 } catch (BindingException e) {
251 throw new RuntimeException(e);
255 } catch(RuntimeException e) {
256 if(e.getCause() instanceof NodeManagerException || e.getCause() instanceof BindingException)
257 throw new DatabaseException(e.getCause());
260 } catch (InterruptedException e) {
261 throw new DatabaseException(e);
264 ExternalSetValue ext = new ExternalSetValue(variable.node.support.manager, variable.node.node,
265 oldValueRef.get(), value, binding);
266 graph.getService(UndoRedoSupport.class).addExternalOperation(graph, ext);
273 Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
274 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
276 modifier.apply(graph, context, value, Bindings.getBinding(value.getClass()));
277 } catch (BindingConstructionException e) {
278 throw new org.simantics.db.exception.BindingException("",e);
283 public static void standardSetValue3(final WriteGraph graph, Variable context, final Object value, final Binding binding) throws DatabaseException {
286 if(context instanceof StandardGraphPropertyVariable) {
288 final StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
291 if(variable.node != null) {
295 variable.node.support.manager.getRealm().syncExec(new Runnable() {
300 Object oldValue = getNodeValue(variable, binding);
301 setNodeValue(variable, value, binding);
302 ExternalSetValue ext = new ExternalSetValue(variable.node.support.manager, variable.node.node, oldValue, value, binding);
303 graph.getService(UndoRedoSupport.class).addExternalOperation(graph, ext);
304 } catch (NodeManagerException | BindingException e) {
305 LOGGER.error("Error setting value", e);
314 } catch (InterruptedException e) {
315 throw new DatabaseException(e);
322 Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
323 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
324 modifier.apply(graph, context, value, binding);
328 public static Datatype getDatatypeFromValue(ReadGraph graph, Variable context) throws DatabaseException {
329 if (context instanceof AbstractVariable) {
330 Binding defaultBinding = ((AbstractVariable)context).getPossibleDefaultBinding(graph);
331 if (defaultBinding != null)
332 return defaultBinding.type();
335 Variant value = context.getVariantValue(graph);
336 if (value.getBinding() == null)
337 throw new DatabaseException("No value binding for " + context.getURI(graph));
339 return value.getBinding().type();
342 @SuppressWarnings("rawtypes")
343 private static class DatatypeGetter implements VariableNodeReadRunnable {
344 final VariableNode node;
348 public DatatypeGetter(VariableNode node) {
352 @SuppressWarnings("unchecked")
356 type = node.support.manager.getDatatype(node.node);
357 } catch (NodeManagerException e) {
362 public String toString() {
363 return "DatatypeGetter(" + node.node + ")";
367 public static Datatype standardGetDatatype(ReadGraph graph, Variable context) throws DatabaseException {
368 if (context instanceof AbstractVariable) {
369 final AbstractVariable variable = (AbstractVariable)context;
370 if (variable.node != null) {
372 DatatypeGetter request = new DatatypeGetter(variable.node);
374 variable.node.support.manager.getRealm().syncExec(request);
376 if (request.exception != null)
377 throw new DatabaseException(request.exception);
380 } catch (InterruptedException e) {
385 return getDatatypeFromValue(graph, context);
388 // @SCLValue(type = "ValueAccessor")
389 // public static ValueAccessor standardValueAccessor = new ValueAccessor() {
392 // public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
393 // return standardGetValue(graph, (StandardGraphPropertyVariable)context);
397 // public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
398 // return standardGetValue(graph, context, binding);
402 // public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
403 // standardSetValue(graph, context, value);
407 // public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
408 // standardSetValue(graph, context, value, binding);
412 // public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
413 // return standardGetDatatype(graph, context);
418 @SCLValue(type = "ValueAccessor")
419 public static ValueAccessor standardValueAccessor = new ValueAccessor() {
422 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
423 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
424 if(accessor != null) return accessor.getValue(graph, context);
426 return standardGetValue1(graph, context);
430 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
431 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
432 if(accessor != null) return accessor.getValue(graph, context, binding);
434 return standardGetValue2(graph, context, binding);
438 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
439 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
440 if(accessor != null) accessor.setValue(graph, context, value);
442 standardSetValue2(graph, context, value);
446 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
447 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
448 if(accessor != null) accessor.setValue(graph, context, value, binding);
450 standardSetValue3(graph, context, value, binding);
454 public Datatype getDatatype(ReadGraph graph, Variable context)
455 throws DatabaseException {
456 ValueAccessor accessor = getPossibleValueValueAccessor(graph, context);
457 if(accessor != null) return accessor.getDatatype(graph, context);
459 return standardGetDatatype(graph, context);
464 public static Variable getStandardChildDomainPropertyVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
465 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
466 PropertyInfo graphProperty = getPossiblePropertyInfoFromContext(graph, variable, variable.resource, name);
467 return getStandardChildDomainPropertyVariable(graph, context, graphProperty, name);
470 public static Resource getPossiblePropertyResource(ReadGraph graph, AbstractVariable parent, Object node) throws DatabaseException {
471 if(parent != null && parent.node != null && parent.node.node != null && parent.node.support != null) {
472 String propertyURI = getPossiblePropertyURI(parent, node);
473 if(propertyURI != null)
474 return graph.getPossibleResource(propertyURI);
479 public static Variable getStandardChildDomainPropertyVariable(ReadGraph graph, Variable context, PropertyInfo graphProperty, String name) throws DatabaseException {
480 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
481 Object propertyNode = getPossibleNodeProperty(graph, variable, name, true);
482 if(graphProperty != null && graphProperty.builder != null)
483 return buildPropertyVariable(graph, variable, variable.resource, graphProperty, propertyNode);
484 if(propertyNode != null) {
485 // Fallback: try to ask property resource uri from NodeManager
486 return createStandardGraphPropertyVariable(graph, variable, propertyNode);
488 // Final fallback: check types corresponding to
489 // node classification(s) and look for asserted
490 // properties from the URIs specified.
491 if (variable.node != null) {
493 @SuppressWarnings("unchecked")
494 Set<String> classifications = variable.node.support.manager.getClassifications(variable.node.node);
495 if (!classifications.isEmpty()) {
496 for (String uri : classifications) {
497 Resource type = graph.syncRequest(
498 new PossibleResource(uri),
499 TransientCacheAsyncListener.instance());
502 Map<String, Pair<PropertyInfo, Resource>> pm = graph.syncRequest(
503 new UnescapedAssertedPropertyMapOfResource(type),
504 TransientCacheAsyncListener.instance());
505 Pair<PropertyInfo, Resource> pi = pm.get(name);
507 return new StandardAssertedGraphPropertyVariable(graph, context, null, type, pi.first.predicate, pi.second);
511 } catch(NodeManagerException e) {
512 throw new DatabaseException(e);
518 public static Map<String, Variable> getStandardChildDomainPropertyVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
519 // Get properties with null identification
520 return getStandardChildDomainPropertyVariables(graph, context, null, map);
523 public static Map<String, Variable> getStandardChildDomainPropertyVariables(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
525 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
527 Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
528 if(!nodeProperties.isEmpty()) {
530 // Get variables for properties read from the graph
531 Map<String,PropertyInfo> graphProperties = collectPropertyInfosFromContext(graph, variable, variable.resource);
533 Set<String> used = new THashSet<String>(nodeProperties.size());
535 map = ensureVariableMap(map, graphProperties.size() + nodeProperties.size());
537 // Process NodeManager property nodes
538 for(Object nodeProperty : nodeProperties) {
539 String name = getNodeName(variable, nodeProperty);
542 PropertyInfo graphProperty = graphProperties.get(name);
543 if(graphProperty != null && graphProperty.builder != null) {
544 if (classification != null && !graphProperty.hasClassification(classification)) continue;
546 // Combine with identically named graph property
547 map.put(name, buildPropertyVariable(graph, variable, variable.resource, graphProperty, nodeProperty));
551 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
554 // Process graph properties
555 for(PropertyInfo info : graphProperties.values()) {
556 String name = info.name;
557 if(used != null && used.contains(name)) continue;
558 if (classification != null && !info.hasClassification(classification)) continue;
559 if (info.builder != null) {
560 map.put(name, buildPropertyVariable(graph, variable, variable.resource, info, null));
567 if(variable.resource == null) return map;
569 // Only graph properties
570 Collection<Resource> predicates = graph.getPredicates(variable.resource);
571 if(predicates.isEmpty()) return map;
573 map = ensureVariableMap(map, predicates.size());
575 // Process graph properties
576 for(Resource predicate : predicates) {
578 PropertyInfo info = //graph.isImmutable(predicate) ?
579 graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance());// :
580 //graph.syncRequest(new PropertyInfoRequest(predicate));
582 if(!info.isHasProperty) continue;
584 if (classification != null && !info.hasClassification(classification)) continue;
585 if (info.builder != null) {
586 map.put(info.name, buildPropertyVariable(graph, variable, variable.resource, info, null));
597 @SCLValue(type = "VariableMap")
598 public static VariableMap standardChildDomainProperties = new VariableMapImpl() {
601 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
602 return getStandardChildDomainPropertyVariable(graph, context, name);
606 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
607 return getStandardChildDomainPropertyVariables(graph, context, map);
612 @SCLValue(type = "VariableMap")
613 public static VariableMap methodsPropertyDomainProperties = new VariableMapImpl() {
616 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
617 Variable parent = context.getParent(graph);
618 Resource container = parent.getPossibleRepresents(graph);
619 if(container == null)
621 Map<String,Resource> methods = graph.syncRequest(new UnescapedMethodMapOfResource(container));
622 Resource predicate = methods.get(name);
623 if(predicate != null) {
624 Layer0 L0 = Layer0.getInstance(graph);
625 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(L0.Entity_method));
626 Resource value = graph.getSingleObject(container, predicate);
627 return new StandardGraphPropertyVariable(context, null, container, info, value);
633 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
634 Variable parent = context.getParent(graph);
635 Resource container = parent.getPossibleRepresents(graph);
636 if(container == null)
637 return Collections.emptyMap();
638 Map<String,Resource> methods = graph.syncRequest(new UnescapedMethodMapOfResource(container));
639 for(Map.Entry<String, Resource> entry : methods.entrySet()) {
640 String name = entry.getKey();
641 Resource predicate = entry.getValue();
642 Layer0 L0 = Layer0.getInstance(graph);
643 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(L0.Entity_method));
644 Resource value = graph.getSingleObject(container, predicate);
645 if(map == null) map = new HashMap<>();
646 map.put(name, new StandardGraphPropertyVariable(context, null, container, info, value));
653 public static Variable getStandardPropertyDomainPropertyVariableFromValue(ReadGraph graph, Variable context, String name) throws DatabaseException {
655 if(context instanceof StandardGraphPropertyVariable) {
656 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
657 Resource literal = variable.getPossibleRepresents(graph);
658 Object propertyNode = getPossibleNodeProperty(graph, variable, name, false);
660 if(literal != null) {
661 Variable result = getPossiblePropertyFromContext(graph, variable, literal, name, propertyNode);
662 if(result != null) return result;
665 Variable result = getPossibleSubliteralPropertyFromContext(graph, variable, name);
666 if(result != null) return result;
667 result = getPossiblePropertyFromContext(graph, variable, variable.property.predicate, name, propertyNode);
668 if (result != null) return result;
670 // Get possible property from NodeManager
671 if (propertyNode != null)
672 return createStandardGraphPropertyVariable(graph, variable, propertyNode);
674 } else if (context instanceof StandardGraphChildVariable) {
675 return standardChildDomainProperties.getVariable(graph, context, name);
677 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
682 public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
684 if(context instanceof StandardGraphPropertyVariable) {
685 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
686 map = collectPropertiesFromContext(graph, variable, variable.property.predicate, map);
687 if (variable.parentResource != null) {
688 Resource literal = graph.getPossibleObject(variable.parentResource, variable.property.predicate);
689 if(literal != null) map=collectPropertiesFromContext(graph, variable, literal, map);
690 map=collectSubliteralProperties(graph, variable, map);
693 // Get properties from VariableNode
694 map = getStandardNodePropertyVariables(graph, context, map);
696 } else if (context instanceof StandardGraphChildVariable) {
697 return standardChildDomainProperties.getVariables(graph, context, map);
699 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
704 public static Map<String, Variable> getStandardPropertyDomainPropertyVariablesFromValue(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
706 if(context instanceof StandardGraphPropertyVariable) {
707 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
708 map = collectPropertiesFromContext(graph, variable, variable.property.predicate, classification, map);
709 if (variable.parentResource != null) {
710 Resource literal = graph.getPossibleObject(variable.parentResource, variable.property.predicate);
711 if(literal != null) map=collectPropertiesFromContext(graph, variable, literal, classification, map);
714 // Get properties from VariableNode
715 map = getStandardNodePropertyVariables(graph, context, map);
717 } else if (context instanceof StandardGraphChildVariable) {
718 return standardChildDomainProperties.getVariables(graph, context, map);
720 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
725 @SCLValue(type = "VariableMap")
726 public static VariableMap standardPropertyDomainProperties = new VariableMapImpl() {
728 VariableMap getValueVariableMap(ReadGraph graph, Variable context) throws DatabaseException {
729 Resource represents = context.getPossibleRepresents(graph);
730 if(represents == null) return null;
732 VariableMap map = graph.isImmutable(represents) ?
733 graph.syncRequest(new PropertyVariableMapRequest(represents), TransientCacheListener.<VariableMap>instance()) :
734 (VariableMap)graph.getPossibleRelatedValue2(represents, Layer0.getInstance(graph).domainProperties, represents);
736 if(map == standardPropertyDomainProperties) return null;
742 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
743 VariableMap valueMap = getValueVariableMap(graph, context);
744 if(valueMap != null) return valueMap.getVariable(graph, context, name);
745 return getStandardPropertyDomainPropertyVariableFromValue(graph, context, name);
749 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
750 VariableMap valueMap = getValueVariableMap(graph, context);
751 if(valueMap != null) return valueMap.getVariables(graph, context, map);
752 else return getStandardPropertyDomainPropertyVariablesFromValue(graph, context, map);
756 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, String classification, Map<String, Variable> map) throws DatabaseException {
757 VariableMap valueMap = getValueVariableMap(graph, context);
758 if(valueMap != null) return valueMap.getVariables(graph, context, classification, map);
759 else return getStandardPropertyDomainPropertyVariablesFromValue(graph, context, classification, map);
764 public static Resource getPossibleGraphChild(ReadGraph graph, Variable variable, String name) throws DatabaseException {
765 Resource resource = variable.getPossibleRepresents(graph);
766 if(resource == null) return null;
767 Map<String, Resource> graphChildren = graph.syncRequest(new UnescapedChildMapOfResource(resource));
768 return graphChildren.get(name);
771 public static Map<String,Resource> getPossibleGraphChildren(ReadGraph graph, Variable variable) throws DatabaseException {
772 Resource resource = variable.getPossibleRepresents(graph);
773 if(resource == null) return Collections.emptyMap();
774 return graph.syncRequest(new UnescapedChildMapOfResource(resource));
777 public static Object getPossibleNodeChild(ReadGraph graph, Variable variable, String name) throws DatabaseException {
778 if (!(variable instanceof AbstractVariable)) return null;
779 VariableNode<?> node = ((AbstractVariable)variable).node;
780 if(node == null) return null;
781 NodeStructure structure = Variables.requestNodeStructure(graph, node);
782 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
783 return structure.children.get(name);
786 public static Collection<Object> getPossibleNodeChildren(ReadGraph graph, Variable variable) throws DatabaseException {
787 if (!(variable instanceof AbstractVariable)) return null;
788 VariableNode<?> node = ((AbstractVariable)variable).node;
789 if(node == null) return Collections.emptyList();
790 NodeStructure structure = Variables.requestNodeStructure(graph, node);
791 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
792 return structure.children.values();
795 public static Object getPossibleNodeProperty(ReadGraph graph, Variable variable, String name, boolean throwPending) throws DatabaseException {
796 if (!(variable instanceof AbstractVariable)) return null;
797 VariableNode<?> node = ((AbstractVariable)variable).node;
798 if(node == null) return null;
799 NodeStructure structure = Variables.requestNodeStructure(graph, node);
800 if(throwPending && Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
801 return structure.properties.get(name);
804 public static Collection<Object> getPossibleNodeProperties(ReadGraph graph, Variable variable) throws DatabaseException {
805 if (!(variable instanceof AbstractVariable)) return null;
806 VariableNode<?> node = ((AbstractVariable)variable).node;
807 if(node == null) return Collections.emptyList();
808 NodeStructure structure = Variables.requestNodeStructure(graph, node);
809 if(Variables.PENDING_NODE_STRUCTURE == structure) throw new PendingVariableException("");
810 return structure.properties.values();
813 @SuppressWarnings({ "rawtypes", "unchecked" })
814 public static VariableNode build(VariableNode parent, Object node) {
815 if(node == null) return null;
816 return new VariableNode(parent.support, node);
820 public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
821 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
825 public static Variable getStandardChildDomainChildVariable(ReadGraph graph, Variable context, Resource graphChild, String name) throws DatabaseException {
826 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, graphChild, name);
830 public static Map<String, Variable> getStandardChildDomainChildVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
831 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
835 public static Map<String, Variable> getStandardChildDomainChildVariables(ReadGraph graph, Variable context, Map<String,Resource> graphChildren, Map<String, Variable> map) throws DatabaseException {
836 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, graphChildren, map);
840 * Get a map of child Variables from a node manager-based Variable, combined with the existing variables in #map.
841 * @param graph The read graph.
842 * @param context The parent Variable.
843 * @param map A map of variables into which the new variables are merged.
844 * @return A map from variable names to instances
845 * @throws DatabaseException
847 public static Map<String, Variable> getStandardNodeChildVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
848 AbstractVariable variable = (AbstractVariable)context;
849 if (variable.node == null) return map;
851 Collection<Object> nodeChildren = getPossibleNodeChildren(graph, variable);
852 if (nodeChildren.isEmpty()) return map;
854 map = ensureVariableMap(map, nodeChildren.size());
856 for(Object nodeChild : nodeChildren) {
857 String name = getNodeName(variable, nodeChild);
858 if (!map.containsKey(name))
859 map.put(name, createStandardGraphChildVariable(variable, nodeChild));
866 * Get a map of property Variables from a node manager-based Variable, combined with the existing variables in #map.
867 * @param graph The read graph.
868 * @param context The parent Variable.
869 * @param map A map of variables into which the new variables are merged.
870 * @return A map from variable names to instances
871 * @throws DatabaseException
873 public static Map<String, Variable> getStandardNodePropertyVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
874 AbstractVariable variable = (AbstractVariable)context;
875 if (variable.node == null) return map;
877 Collection<Object> nodeProperties = getPossibleNodeProperties(graph, variable);
878 if (nodeProperties.isEmpty()) return map;
880 map = ensureVariableMap(map, nodeProperties.size());
882 for(Object nodeProperty : nodeProperties) {
883 String name = getNodeName(variable, nodeProperty);
884 if (!map.containsKey(name)) {
885 map.put(name, createStandardGraphPropertyVariable(graph, variable, nodeProperty));
892 @SCLValue(type = "VariableMap")
893 public static VariableMap standardChildDomainChildren = new VariableMapImpl() {
896 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
897 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, name);
901 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
902 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, map);
907 @SCLValue(type = "VariableMap")
908 public static VariableMap standardPropertyDomainChildren = new VariableMapImpl() {
911 * Get a possible non-standard VariableMap defined in the graph.
912 * @param graph The graph
913 * @param context The context node
914 * @return A non-standard VariableMap instance for the context node,
915 * or null, if not defined or defined as this instance.
916 * @throws DatabaseException
918 VariableMap getValueVariableMap(ReadGraph graph, Variable context) throws DatabaseException {
919 Resource represents = context.getPossibleRepresents(graph);
920 if(represents == null) return null;
921 VariableMap map = graph.syncRequest(new ChildVariableMapRequest(represents));
922 if(map == standardPropertyDomainChildren) return null;
927 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
928 // Delegate call to a non-standard variable map?
929 VariableMap valueMap = getValueVariableMap(graph, context);
930 if(valueMap != null) return valueMap.getVariable(graph, context, name);
932 if(context instanceof StandardGraphPropertyVariable) {
933 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
934 Datatype dt = variable.getDatatype(graph);
935 if (dt instanceof ArrayType) {
936 ChildReference ref = getPossibleIndexReference(name);
938 return new SubliteralPropertyVariableDeprecated(variable, ref);
941 // Check for a child node provided by the NodeManager
942 if (variable.node != null) {
943 Object childNode = getPossibleNodeChild(graph, variable, name);
944 if (childNode != null)
945 return createStandardGraphChildVariable(variable, childNode);
947 return standardChildDomainChildren.getVariable(graph, context, name);
948 } else if (context instanceof StandardGraphChildVariable) {
949 return standardChildDomainChildren.getVariable(graph, context, name);
951 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
956 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
957 // Delegate call to a non-standard variable map?
958 VariableMap valueMap = getValueVariableMap(graph, context);
959 if(valueMap != null) return valueMap.getVariables(graph, context, map);
961 if(context instanceof StandardGraphPropertyVariable) {
962 // Get child variables provided by the NodeManager
963 Map<String, Variable> result = getStandardNodeChildVariables(graph, context, map);
964 return standardChildDomainChildren.getVariables(graph, context, result);
965 } else if (context instanceof StandardGraphChildVariable) {
966 return standardChildDomainChildren.getVariables(graph, context, map);
968 throw new DatabaseException("Unknown variable implementation " + context.getClass().getCanonicalName());
974 protected static ChildReference getPossibleIndexReference(String name) {
975 if (name.startsWith("i-")) {
977 int index = Integer.parseInt(name.substring(2));
978 return new IndexReference(index);
979 } catch (NumberFormatException e) {}
984 protected static ValueAccessor getPossiblePropertyValueAccessor(ReadGraph graph, StandardGraphPropertyVariable variable) throws DatabaseException {
985 if(variable.property == null) return null;
986 return variable.property.valueAccessor;
987 // return graph.syncRequest(new PropertyValueAccessorRequest(variable.property), TransientCacheAsyncListener.<ValueAccessor>instance());
988 // return graph.syncRequest(new PossibleRelatedValueImplied2<ValueAccessor>(variable.property, Layer0.getInstance(graph).valueAccessor));
991 public static ValueAccessor getPossibleValueValueAccessor(ReadGraph graph, Variable variable) throws DatabaseException {
992 Resource value = variable.getPossibleRepresents(graph);
993 if(value == null) return null;
994 //return graph.syncRequest(new PropertyValueAccessorRequest(value));
995 return graph.syncRequest(new PossibleRelatedValueImplied2<ValueAccessor>(value, Layer0.getInstance(graph).valueAccessor));
998 public static PropertyInfo getPossiblePropertyInfoFromContext(ReadGraph graph, Variable variable, Resource context, String name) throws DatabaseException {
999 if(context == null) return null;
1000 Map<String, PropertyInfo> predicates = graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheListener.instance());
1001 return predicates.get(name);
1004 public static Variable getPossiblePropertyFromContext(ReadGraph graph, Variable variable, Resource context, String name, Object propertyNode) throws DatabaseException {
1005 PropertyInfo info = getPossiblePropertyInfoFromContext(graph, variable, context, name);
1006 if(info == null || info.builder == null) return null;
1007 return buildPropertyVariable(graph, variable, context, info, propertyNode);
1010 public static Variable getPossibleSubliteralPropertyFromContext(ReadGraph graph, StandardGraphPropertyVariable variable, String name) throws DatabaseException {
1012 Resource predicate = variable.property.predicate;
1013 if(predicate == null) return null;
1015 PropertyInfo info = getPropertyInfo(graph, predicate);
1016 Pair<Resource, ChildReference> p = info.subliteralPredicates.get(name);
1017 if(p == null) return null;
1019 return new SubliteralPropertyVariable(graph, variable, p.first, p.second);
1023 public static Map<String, PropertyInfo> collectPropertyInfosFromContext(ReadGraph graph, Variable variable, Resource context) throws DatabaseException {
1024 if(context == null) return Collections.emptyMap();
1025 return graph.isImmutable(context) ?
1026 graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance()) :
1027 graph.syncRequest(new UnescapedPropertyMapOfResource(context));
1030 public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, Map<String, Variable> map) throws DatabaseException {
1032 Map<String,PropertyInfo> properties = graph.isImmutable(context) ?
1033 graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance()) :
1034 graph.syncRequest(new UnescapedPropertyMapOfResource(context));
1036 if(properties.isEmpty()) return map;
1038 map = ensureVariableMap(map, properties.size());
1040 for(PropertyInfo info : properties.values()) {
1041 String name = info.name;
1042 if (info.builder != null) {
1043 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1052 public static Map<String, Variable> collectSubliteralProperties(ReadGraph graph, StandardGraphPropertyVariable variable, Map<String, Variable> map) throws DatabaseException {
1054 Resource predicate = variable.property.predicate;
1055 if(predicate == null) return map;
1057 PropertyInfo info = getPropertyInfo(graph, predicate);
1058 if(info.subliteralPredicates.isEmpty()) return map;
1060 map = ensureVariableMap(map, info.subliteralPredicates.size());
1062 for(Map.Entry<String, Pair<Resource, ChildReference>> entry : info.subliteralPredicates.entrySet()) {
1063 String key = entry.getKey();
1064 Pair<Resource, ChildReference> p = entry.getValue();
1065 if(map == null) map = new THashMap<String,Variable>();
1066 map.put(key, new SubliteralPropertyVariable(graph, variable, p.first, p.second));
1073 public static Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Variable variable, Resource context, String classification, Map<String, Variable> map) throws DatabaseException {
1075 if(graph.isImmutable(context)) {
1077 Map<String,PropertyInfo> properties = graph.syncRequest(new UnescapedPropertyMapOfResource(context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance());
1078 for(PropertyInfo info : properties.values()) {
1080 if(info.classifications.contains(classification) && info.builder != null) {
1081 String name = info.name;
1082 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1083 if(map == null) map = new THashMap<String,Variable>();
1091 Collection<Resource> predicates = graph.getPredicates(context);
1093 if(predicates.isEmpty()) return map;
1095 map = ensureVariableMap(map, predicates.size());
1097 for(Resource predicate : predicates) {
1099 PropertyInfo info = graph.isImmutable(predicate) ?
1100 graph.syncRequest(new PropertyInfoRequest(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
1101 graph.syncRequest(new PropertyInfoRequest(predicate));
1103 if(!info.isHasProperty) continue;
1105 if(info.classifications.contains(classification) && info.builder != null) {
1106 String name = info.name;
1107 Variable v = info.builder.buildProperty(graph, variable, null, context, info.predicate);
1108 if(map == null) map = new THashMap<String,Variable>();
1120 @SCLValue(type = "ReadGraph -> Resource -> a -> String")
1121 public static String entityLabel(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1122 if(context instanceof Resource) {
1123 return NameUtils.getSafeLabel(graph, ((Resource)context));
1124 } else if (context instanceof Variable) {
1125 Variable parent = ((Variable)context).getParent(graph);
1126 Resource represents = parent.getRepresents(graph);
1127 return NameUtils.getSafeLabel(graph, represents);
1129 throw new DatabaseException("Unknown context " + context);
1133 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1134 public static Object listResources(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1135 return ListUtils.toList(graph, resource);
1138 @SCLValue(type = "ReadGraph -> Resource -> Variable -> [String]")
1139 public static List<String> standardClassifications(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1140 ArrayList<String> result = new ArrayList<String>();
1141 Resource predicate = context.getParent(graph).getPossiblePredicateResource(graph);
1142 if(predicate != null) {
1143 for(Resource type : graph.getTypes(predicate)) {
1144 String uri = graph.getPossibleURI(type);
1145 if(uri != null) result.add(uri);
1151 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1152 public static Boolean standardValidValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1153 return Boolean.TRUE;
1156 @SCLValue(type = "ReadGraph -> Resource -> a -> StringInputValidator")
1157 public static StringInputValidator standardValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1158 return StringInputValidator.PASS;
1161 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1162 public static Boolean standardRequiredValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1163 return Boolean.FALSE;
1166 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Boolean")
1167 public static Boolean standardDefaultValue(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1168 Variable property = context.getParent(graph);
1169 if(property instanceof StandardGraphPropertyVariable) {
1170 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)property;
1171 if (variable.parentResource != null) {
1172 Resource predicate = variable.getPossiblePredicateResource(graph);
1173 if (predicate != null) {
1174 Statement stm = graph.getPossibleStatement(variable.parentResource, predicate);
1175 return stm != null && stm.isAsserted(variable.parentResource);
1179 return Boolean.FALSE;
1182 @SCLValue(type = "ReadGraph -> Resource -> a -> Boolean")
1183 public static Boolean standardReadOnlyValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1184 return Boolean.FALSE;
1187 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1188 public static Object resourceAsValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1192 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1193 public static Object functionApplication(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1194 return Functions.exec(graph, resource, graph, resource, context);
1197 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1198 public static Object computeExpression(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1199 if(context instanceof Variable) {
1200 return CompileValueRequest.compileAndEvaluate(graph, (Variable)context);
1201 } if (context instanceof Resource) {
1202 return CompileResourceValueRequest.compileAndEvaluate(graph, (Resource)converter);
1204 throw new IllegalStateException("Unknown context " + context);
1208 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1209 public static Object composedPropertyValue(ReadGraph graph, Resource converter, Object context) throws DatabaseException {
1210 if(context instanceof Variable) {
1211 return new StandardComposedProperty();
1212 } if (context instanceof Resource) {
1213 return new StandardComposedProperty();
1215 throw new IllegalStateException("Unknown context " + context);
1219 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1220 public static Object numberInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1222 class Validator extends FunctionImpl1<String, String> {
1224 private final Datatype datatype;
1226 public Validator(Datatype datatype) {
1227 this.datatype = datatype;
1231 public String apply(String input) {
1233 if(datatype == null) return null;
1237 if(datatype instanceof NumberType) {
1239 Number number = (Number)PrimitiveValueParser.parse(input, datatype);
1240 NumberType nt = (NumberType)datatype;
1241 Range r = nt.getRange();
1243 if(!r.contains(number)) return "Value is out of valid range";
1248 } catch (NumberFormatException e) {
1249 return "Not a valid floating-point number";
1250 } catch (IllegalArgumentException e) {
1251 return "Not a valid floating-point number";
1258 if(context instanceof Variable) {
1260 Variable variable = (Variable)context;
1261 Variable property = variable.getParent(graph);
1262 Datatype datatype = property.getPossibleDatatype(graph);
1263 return new Validator(datatype);
1265 } else if (context instanceof Resource) {
1267 Layer0 L0 = Layer0.getInstance(graph);
1268 Resource literal = (Resource)context;
1269 Datatype datatype = graph.getRelatedValue(literal, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
1270 return new Validator(datatype);
1274 return new Validator(null);
1280 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
1281 public static Object booleanInputValidator(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
1283 return new FunctionImpl1<String, String>() {
1286 public String apply(String input) {
1288 String lower = input.toLowerCase();
1289 if("true".equals(lower) || "false".equals(lower)) return null;
1291 return "Not a valid boolean: " + input;
1299 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Resource")
1300 public static Resource hasStandardResource(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
1301 Variable parent = context.getParent(graph);
1302 if(parent instanceof StandardGraphChildVariable) {
1303 StandardGraphChildVariable variable = (StandardGraphChildVariable)parent;
1304 return variable.resource;
1310 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1311 public static Object valueWithoutBinding(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1313 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1315 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1316 Layer0 L0 = Layer0.getInstance(graph);
1317 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel);
1320 if (variable.parentResource == null)
1321 throw new InvalidVariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").");
1324 return graph.getRelatedValue2(variable.parentResource, variable.getPredicateResource(graph), variable);
1325 } catch (NoSingleResultException e) {
1326 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1327 } catch (DoesNotContainValueException e) {
1328 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1333 @SCLValue(type = "ReadGraph -> Variable -> Binding -> a")
1334 public static Object valueWithBinding(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
1336 StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
1338 if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
1339 Layer0 L0 = Layer0.getInstance(graph);
1340 return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
1343 if (variable.parentResource == null)
1344 throw new MissingVariableException("Variable is not represented by any resource (URI=" + variable.getPossibleURI(graph) + ").", context.getPossibleRepresents(graph));
1348 return graph.getRelatedValue2(variable.parentResource, variable.getPredicateResource(graph), variable);
1349 } catch (NoSingleResultException e) {
1350 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1351 } catch (DoesNotContainValueException e) {
1352 throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
1357 @SCLValue(type = "WriteGraph -> Variable -> a -> Binding -> b")
1358 public static Object valueSetterWithBinding(WriteGraph graph, Variable variable, Object value, Binding binding) throws DatabaseException {
1360 Function4<WriteGraph, Variable, Object, Object, String> modifier = variable.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
1361 if(modifier == null) modifier = VariableUtils.defaultInputModifier;
1362 modifier.apply(graph, variable, value, binding);
1367 static class L0Issue extends StandardIssue {
1369 private final String description;
1371 public L0Issue(String description, Resource type, Resource ... contexts) {
1372 super(type, contexts);
1373 this.description = description;
1377 public Resource write(WriteGraph graph, Resource source) throws DatabaseException {
1378 Layer0 L0 = Layer0.getInstance(graph);
1379 IssueResource IR = IssueResource.getInstance(graph);
1380 Resource issue = super.write(graph, source);
1381 graph.claim(issue, IR.Issue_HasSeverity, IR.Severity_Fatal);
1382 graph.addLiteral(issue, L0.HasDescription, L0.HasDescription_Inverse, description, Bindings.STRING);
1388 private static List<Issue> reportInconsistency(ReadGraph graph, Resource subject, String description, List<Issue> issues) throws DatabaseException {
1389 if(issues == null) issues = new ArrayList<Issue>();
1390 System.err.println("Change set validation reports the following issue: " + NameUtils.getSafeName(graph, subject, true) + ": " + description);
1391 IssueResource IR = IssueResource.getInstance(graph);
1392 issues.add(new L0Issue(description, IR.Issue, subject));
1396 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1397 public static List<Issue> relationValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1399 Layer0 L0 = Layer0.getInstance(graph);
1401 List<Issue> issues = null;
1403 for(Statement stm : graph.getStatements(resource, L0.IsWeaklyRelatedTo)) {
1404 Resource predicate = stm.getPredicate();
1405 Resource object = stm.getObject();
1406 if(!isRelation(graph, L0, predicate)) {
1407 issues = reportInconsistency(graph, resource, "The predicate of a statement must be a relation: " + NameUtils.toString(graph, stm), issues);
1409 if(graph.isInstanceOf(predicate, L0.FunctionalRelation)) {
1410 if(graph.getObjects(resource, predicate).size() > 1)
1411 issues = reportInconsistency(graph, resource,
1413 NameUtils.getSafeName(graph, predicate)
1414 + " is functional.", issues);
1417 Collection<Resource> domain = graph.getObjects(predicate, L0.HasDomain);
1418 if (!isInstanceOfAny(graph, resource, domain, true)) {
1419 StringBuilder sb = new StringBuilder()
1420 .append("The domain of ")
1421 .append(NameUtils.getSafeName(graph, predicate))
1422 .append(" relation is ");
1423 orString(graph, sb, domain).append(".");
1424 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1428 Collection<Resource> range = graph.getObjects(predicate, L0.HasRange);
1429 if (!isInstanceOfAny(graph, object, range, true) && !graph.isInstanceOf(object, L0.SCLValue)) {
1430 StringBuilder sb = new StringBuilder()
1431 .append("The range of ")
1432 .append(NameUtils.getSafeName(graph, predicate))
1433 .append(" relation is ");
1434 orString(graph, sb, range).append(" but current object is ")
1435 .append(NameUtils.getSafeName(graph, object)).append(".");
1436 issues = reportInconsistency(graph, resource, sb.toString(), issues);
1441 return issues != null ? issues : Collections.<Issue>emptyList();
1445 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1446 public static List<Issue> propertyValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1448 List<Issue> issues = null;
1450 Layer0 L0 = Layer0.getInstance(graph);
1451 for(Statement stm : graph.getStatements(resource, L0.HasProperty)) {
1452 Resource subject = stm.getSubject();
1453 Resource predicate = stm.getPredicate();
1454 String error = L0Validations.checkValueType(graph, subject, predicate);
1455 if(error != null) issues = reportInconsistency(graph, subject, error, issues);
1458 return issues != null ? issues : Collections.<Issue>emptyList();
1463 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1464 public static List<Issue> valueValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1466 List<Issue> issues = null;
1468 Layer0 L0 = Layer0.getInstance(graph);
1469 if(graph.hasValue(resource)) {
1470 if(!graph.isInstanceOf(resource, L0.Literal)) {
1471 issues = reportInconsistency(graph, resource,
1472 "Resource has a value but it is not a literal.", issues);
1475 // TODO check that the value is valid for the data type
1479 if(graph.isInstanceOf(resource, L0.Literal)) {
1480 issues = reportInconsistency(graph, resource,
1481 "Resource is a literal but it does not have a value.", issues);
1485 return issues != null ? issues : Collections.<Issue>emptyList();
1490 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1491 public static List<Issue> uriValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1493 List<Issue> issues = null;
1495 Layer0 L0 = Layer0.getInstance(graph);
1496 Resource parent = graph.getPossibleObject(resource, L0.PartOf);
1497 if(parent != null) {
1498 String parentURI = graph.syncRequest(new PossibleURI(parent));
1499 if(parentURI != null) {
1500 String name = graph.getPossibleRelatedValue(resource, L0.HasName);
1502 issues = reportInconsistency(graph, resource, "Resource has a parent with URI but has no valid HasName.", issues);
1507 return issues != null ? issues : Collections.<Issue>emptyList();
1511 private static Resource getPossibleNearestClusterSet(ReadGraph graph, Resource base, Resource resource) throws DatabaseException {
1513 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1514 if(cs.isClusterSet(resource) && !base.equals(resource)) return resource;
1516 Resource nearest = NearestOwnerFinder.getNearestOwner(graph, resource);
1517 if(nearest == null) return null;
1519 return getPossibleNearestClusterSet(graph, base, nearest);
1523 private static boolean quirks(ReadGraph graph, Resource resource) throws DatabaseException {
1525 if(!resource.isPersistent()) return true;
1526 if(graph.isImmutable(resource)) return true;
1527 if(resource.getResourceId() < 0x2000) return true;
1533 @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
1534 public static List<Issue> clusterValidator(ReadGraph graph, Resource resource) throws DatabaseException {
1536 if(!Development.DEVELOPMENT) return Collections.<Issue>emptyList();
1538 if(quirks(graph, resource)) return Collections.<Issue>emptyList();
1540 List<Issue> issues = null;
1542 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1543 Resource set = cs.getClusterSetOfCluster(resource);
1545 if(set == null) return reportInconsistency(graph, resource, "Resource cluster is not part of any cluster set", issues);
1547 Resource nearestSet = getPossibleNearestClusterSet(graph, resource, resource);
1548 if(nearestSet == null) {
1549 // This means that there is no owner since RootLibrary is a cluster set
1550 return Collections.<Issue>emptyList();
1553 if(!set.equals(nearestSet)) return reportInconsistency(graph, resource, "The cluster set of a resource is not the nearest owner set", issues);
1555 return Collections.<Issue>emptyList();
1559 private static boolean isInstanceOfAny(ReadGraph graph, Resource r, Collection<Resource> types, boolean ifEmpty) throws DatabaseException {
1560 if (types.isEmpty())
1562 for (Resource type : types) {
1563 if (graph.isInstanceOf(r, type)) {
1570 private static StringBuilder orString(ReadGraph graph, StringBuilder sb, Collection<Resource> rs) throws DatabaseException {
1572 boolean first = true;
1573 for (Resource r : rs) {
1577 sb.append(NameUtils.getSafeName(graph, r));
1583 public static boolean isRelation(ReadGraph g, Layer0 l0, Resource relation) throws DatabaseException {
1584 return g.hasStatement(relation, l0.SubrelationOf) || relation == l0.IsWeaklyRelatedTo;
1587 public static boolean isType(ReadGraph g, Layer0 l0, Resource type) throws DatabaseException {
1588 return g.hasStatement(type, l0.Inherits) || type == l0.Entity;
1591 public static Variable buildChildVariable(ReadGraph graph, Variable context, Resource graphChild, Object nodeChild) throws DatabaseException {
1592 VariableBuilder builder = graph.adapt(graphChild, VariableBuilder.class);
1593 return builder.buildChild(graph, context, build(((AbstractVariable)context).node, nodeChild), graphChild);
1596 private static Variable buildPropertyVariable(ReadGraph graph, Variable variable, Resource parentResource, PropertyInfo graphProperty, Object propertyNode) throws DatabaseException {
1597 VariableNode<?> node = variable instanceof AbstractVariable ? build(((AbstractVariable)variable).node, propertyNode) : null;
1598 return graphProperty.builder.buildProperty(graph, variable, node, parentResource, graphProperty.predicate);
1601 static StandardGraphChildVariable createStandardGraphChildVariable(
1602 AbstractVariable parent, Object child) {
1603 return new StandardGraphChildVariable(parent, build(parent.node, child), null);
1606 private static StandardGraphPropertyVariable createStandardGraphPropertyVariable(
1607 ReadGraph graph, AbstractVariable variable, Object nodeProperty) throws DatabaseException {
1608 Resource propertyResource = getPossiblePropertyResource(graph, variable, nodeProperty);
1609 return new StandardGraphPropertyVariable(graph, variable, build(variable.node, nodeProperty), null, propertyResource);
1612 static Map<String, Variable> ensureVariableMap(
1613 Map<String, Variable> map, int size) {
1614 if(map == null) map = new THashMap<String,Variable>(size);
1618 private static PropertyInfo getPropertyInfo(ReadGraph graph, Resource predicate) throws DatabaseException {
1619 return graph.syncRequest(new PropertyInfoRequest(predicate));
1622 @SuppressWarnings("unchecked")
1623 static String getNodeName(AbstractVariable parent, Object child) {
1624 return parent.node.support.manager.getName(child);
1627 @SuppressWarnings("unchecked")
1628 private static Object getNodeValue(final AbstractVariable variable, final Binding binding) throws NodeManagerException, BindingException {
1629 return variable.node.support.manager.getValue(variable.node.node, binding);
1632 @SuppressWarnings("unchecked")
1633 private static void setNodeValue(final AbstractVariable variable, final Object value, final Binding binding) throws NodeManagerException, BindingException {
1634 variable.node.support.manager.setValue(variable.node.node, value, binding);
1637 @SuppressWarnings("unchecked")
1638 private static String getPossiblePropertyURI(AbstractVariable parent, Object node) {
1639 return parent.node.support.manager.getPropertyURI(parent.node.node, node);
1643 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1644 public static Object defaultInstantiateUnder(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1645 return new FunctionImpl2<Resource, Resource, Resource>() {
1646 public Resource apply(Resource container, Resource type) {
1648 WriteGraph graph = (WriteGraph)SCLContext.getCurrent().get("graph");
1650 Layer0 L0 = Layer0.getInstance(graph);
1651 CommonDBUtils.selectClusterSet(graph, container);
1652 Resource result = graph.newResource();
1653 String name = NameUtils.findFreshInstanceName(graph, type, container);
1654 graph.claim(result, L0.InstanceOf, type);
1655 graph.addLiteral(result, L0.HasName, L0.NameOf, name, Bindings.STRING);
1656 graph.claim(container, L0.ConsistsOf, L0.PartOf, result);
1659 } catch (DatabaseException e) {
1660 throw new RuntimeDatabaseException(e);