1 package org.simantics.db.layer0.variable;
3 import java.util.Collection;
4 import java.util.Collections;
5 import java.util.HashMap;
9 import org.simantics.databoard.Bindings;
10 import org.simantics.databoard.accessor.reference.ChildReference;
11 import org.simantics.databoard.binding.Binding;
12 import org.simantics.databoard.binding.impl.ObjectVariantBinding;
13 import org.simantics.databoard.type.Datatype;
14 import org.simantics.db.DevelopmentKeys;
15 import org.simantics.db.ReadGraph;
16 import org.simantics.db.Resource;
17 import org.simantics.db.WriteGraph;
18 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
19 import org.simantics.db.common.validation.L0Validations;
20 import org.simantics.db.exception.DatabaseException;
21 import org.simantics.db.exception.DatatypeNotFoundException;
22 import org.simantics.db.exception.ValidationException;
23 import org.simantics.db.layer0.exception.InvalidVariableException;
24 import org.simantics.db.layer0.exception.MissingVariableException;
25 import org.simantics.db.layer0.exception.MissingVariableValueException;
26 import org.simantics.db.layer0.exception.PendingVariableException;
27 import org.simantics.db.layer0.function.All;
28 import org.simantics.db.layer0.request.PropertyInfo;
29 import org.simantics.db.layer0.request.PropertyInfoRequest;
30 import org.simantics.db.layer0.scl.SCLDatabaseException;
31 import org.simantics.db.layer0.util.Layer0Utils;
32 import org.simantics.layer0.Layer0;
33 import org.simantics.utils.Development;
34 import org.simantics.utils.datastructures.Pair;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 public class StandardGraphPropertyVariable extends AbstractPropertyVariable {
40 private static final Logger LOGGER = LoggerFactory.getLogger(StandardGraphPropertyVariable.class);
42 protected static final PropertyInfo NO_PROPERTY = new PropertyInfo(null, null, true,
43 false, false, Collections.<String> emptySet(), null, null, null, null, null, null,
44 Collections.<String, Pair<Resource, ChildReference>> emptyMap(),
47 final public Variable parent;
48 final public Resource parentResource;
49 final public PropertyInfo property;
50 final public Resource represents;
52 transient private int hash = 0;
54 public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, VariableNode node, Resource property) throws DatabaseException {
55 this(graph, parent, node, (Resource)parent.getPossibleRepresents(graph), getPropertyInfo(graph, property));
58 public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, VariableNode node, Resource parentResource, Resource property) throws DatabaseException {
59 this(graph, parent, node, parentResource, getPropertyInfo(graph, property));
62 public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, Resource property) throws DatabaseException {
63 this(graph, parent, null, (Resource)parent.getPossibleRepresents(graph), getPropertyInfo(graph, property));
66 public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, Resource parentResource, PropertyInfo property) throws DatabaseException {
67 this(parent, null, parentResource, property, getPossibleRepresents(graph, parentResource, property.predicate));
70 public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, VariableNode node, Resource parentResource, PropertyInfo property) throws DatabaseException {
71 this(parent, node, parentResource, property, getPossibleRepresents(graph, parentResource, property.predicate));
74 private static PropertyInfo getPropertyInfo(ReadGraph graph, Resource property) throws DatabaseException {
75 return property != null ? graph.syncRequest(new PropertyInfoRequest(property), TransientCacheAsyncListener.<PropertyInfo>instance()) : NO_PROPERTY;
78 private static Resource getPossibleRepresents(ReadGraph graph, Resource parentResource, Resource predicate) throws DatabaseException {
79 if(parentResource == null || predicate == null) return null;
80 return graph.getPossibleObject(parentResource, predicate);
83 public boolean isAsserted() {
87 public StandardGraphPropertyVariable(Variable parent, VariableNode node, Resource parentResource, PropertyInfo property, Resource represents) throws DatabaseException {
89 assert parent != null;
91 this.property = property;
92 this.parentResource = parentResource;
93 this.represents = represents;
97 public String getName(ReadGraph graph) throws DatabaseException {
98 if(node != null) return node.support.manager.getName(node.node);
103 public String getPossibleLabel(ReadGraph graph) throws DatabaseException {
104 if (property.predicate == null)
106 return graph.getPossibleRelatedValue2(property.predicate, graph.getService(Layer0.class).HasLabel, parent, Bindings.STRING);
110 public String getLabel(ReadGraph graph) throws DatabaseException {
111 if (property.predicate == null)
112 throw new NoPredicateResourceException("No predicate resource for property " + getName(graph));
113 return graph.getRelatedValue2(property.predicate, graph.getService(Layer0.class).HasLabel, parent, Bindings.STRING);
117 public Variable getParent(ReadGraph graph) throws DatabaseException {
122 public PropertyInfo getPropertyInfo(ReadGraph graph) throws DatabaseException {
126 @SuppressWarnings("unchecked")
128 public <T> T getValue(ReadGraph graph) throws DatabaseException {
130 if(Development.DEVELOPMENT) {
131 if(Development.<Boolean>getProperty(DevelopmentKeys.L0_VALIDATION, Bindings.BOOLEAN)) {
132 if (property.predicate != null) {
133 String error = L0Validations.checkValueType(graph, parentResource, property.predicate);
136 throw new ValidationException(error);
142 return (T)getValueAccessor(graph).getValue(graph, this);
146 @SuppressWarnings("unchecked")
148 public <T> T getValue(ReadGraph graph, Binding binding) throws DatabaseException {
149 // Fall back to the bindingless method, if the expected output is a Java object
150 if (binding instanceof ObjectVariantBinding)
151 return getValue(graph);
153 if(Development.DEVELOPMENT) {
154 if(Development.<Boolean>getProperty(DevelopmentKeys.L0_VALIDATION, Bindings.BOOLEAN)) {
155 if (property.predicate != null) {
156 String error = L0Validations.checkValueType(graph, parentResource, property.predicate);
159 throw new ValidationException(error);
167 return (T) getValueAccessor(graph).getValue(graph, this, binding);
168 } catch (SCLDatabaseException e) { // these can be thrown when compiling e.g. derived properties
170 } catch (MissingVariableValueException | PendingVariableException e) {
172 } catch (Throwable t) {
173 throw new MissingVariableValueException(t);
179 public Resource getRepresents(ReadGraph graph) throws DatabaseException {
180 if(represents == null)
181 throw new InvalidVariableException("Variable is not represented by any resource (URI=" + getPossibleURI(graph) + ").");
186 public Resource getPossibleRepresents(ReadGraph graph) throws DatabaseException {
191 public void setValue(WriteGraph graph, Object value, Binding binding) throws DatabaseException {
193 if(Development.DEVELOPMENT) {
194 if(Development.<Boolean>getProperty(DevelopmentKeys.L0_VALIDATION, Bindings.BOOLEAN)) {
195 if (property.predicate != null) {
196 String error = L0Validations.checkValueType(graph, parentResource, property.predicate);
199 throw new ValidationException(error);
205 getValueAccessor(graph).setValue(graph, this, value, binding);
210 public void setValue(WriteGraph graph, Object value) throws DatabaseException {
212 if(Development.DEVELOPMENT) {
213 if(Development.<Boolean>getProperty(DevelopmentKeys.L0_VALIDATION, Bindings.BOOLEAN)) {
214 if (property.predicate != null) {
215 String error = L0Validations.checkValueType(graph, parentResource, property.predicate);
218 throw new ValidationException(error);
224 getValueAccessor(graph).setValue(graph, this, value);
229 public Binding getDefaultBinding(ReadGraph graph) throws DatabaseException {
230 return Layer0Utils.getDefaultBinding(graph, this);
234 public Binding getPossibleDefaultBinding(ReadGraph graph) throws DatabaseException {
235 return Layer0Utils.getPossibleDefaultBinding(graph, this);
239 public Datatype getDatatype(ReadGraph graph) throws DatabaseException {
242 type = getValueAccessor(graph).getDatatype(graph, this);
243 } catch (Throwable t) {
244 throw new MissingVariableValueException(t);
248 String uri = this.getPossibleURI(graph);
250 throw new DatatypeNotFoundException("No data type for " + uri);
252 throw new DatatypeNotFoundException("No data type for " + this.getIdentifier());
260 public Datatype getPossibleDatatype(ReadGraph graph) throws DatabaseException {
263 return getDatatype(graph);
264 } catch (DatabaseException e) {
271 public String getUnit(ReadGraph graph) throws DatabaseException {
273 return Layer0Utils.getUnit(graph, this);
274 } catch (DatabaseException e) {
280 public Resource getPropertyResource(ReadGraph graph) {
281 return property.predicate;
285 public Resource getContainerResource(ReadGraph graph) throws DatabaseException {
286 return parentResource;
290 public Collection<Variable> getChildren(ReadGraph graph) throws DatabaseException {
292 Map<String, Variable> result = new HashMap<String, Variable>();
293 VariableMap map = getPossibleChildVariableMap(graph);
294 if(map != null) map.getVariables(graph, this, result);
295 return result.values();
300 public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException {
302 VariableMap map = getPossibleChildVariableMap(graph);
303 if(map == null) return null;
305 return map.getVariable(graph, this, name);
306 } catch (DatabaseException e) {
314 protected Variable getPossibleDomainProperty(ReadGraph graph, String name) throws DatabaseException {
316 VariableMap valueMap = getPossiblePropertyVariableMap(graph);
317 if(valueMap == null) return null;
319 return valueMap.getVariable(graph, this, name);
320 } catch (DatabaseException e) {
322 } catch (Exception t) {
323 LOGGER.error("getPossibleDomainProperty is implemented incorrectly, but returns null on Exception for backward compatibility. URI="+getURI(graph)+", name="+name+".", t);
330 public Map<String, Variable> collectDomainProperties(ReadGraph graph, Map<String, Variable> properties) throws DatabaseException {
332 VariableMap valueMap = getPossiblePropertyVariableMap(graph);
333 if(valueMap == null) return properties;
334 return valueMap.getVariables(graph, this, properties);
339 public Variable getPredicate(ReadGraph graph) throws DatabaseException {
340 if (property.predicate == null)
341 throw new MissingVariableException("No predicate for property " + getName(graph));
342 return Variables.getVariable(graph, graph.getURI(property.predicate));
346 public Resource getPredicateResource(ReadGraph graph) throws DatabaseException {
347 if (property.predicate == null)
348 throw new NoPredicateResourceException("No predicate for property " + getName(graph));
349 return property.predicate;
353 public Resource getPossiblePredicateResource(ReadGraph graph) throws DatabaseException {
354 return property.predicate;
358 public int hashCode() {
360 final int prime = 31;
362 result = prime * result + (parent != null ? parent.hashCode() : 0);
363 result = prime * result + (node != null ? node.hashCode() : 0);
364 result = prime * result + (property.predicate != null ? property.predicate.hashCode() : 0);
365 result = prime * result + (parentResource != null ? parentResource.hashCode() : 0);
366 result = prime * result + (represents != null ? represents.hashCode() : 0);
373 public boolean equals(Object obj) {
378 if (getClass() != obj.getClass())
380 StandardGraphPropertyVariable other = (StandardGraphPropertyVariable) obj;
383 if(!node.equals(other.node)) return false;
384 } else if (other.node != null) return false;
386 if(property.predicate != null) {
387 if(!property.predicate.equals(other.property.predicate)) return false;
388 } else if (other.property.predicate != null) return false;
390 if(parentResource != null) {
391 if(!parentResource.equals(other.parentResource)) return false;
392 } else if (other.parentResource != null) return false;
395 if(!parent.equals(other.parent)) return false;
396 } else if (other.parent != null) return false;
398 if(represents != null) {
399 if(!represents.equals(other.represents)) return false;
400 } else if (other.represents != null) return false;
407 protected Variable getNameVariable(ReadGraph graph) throws DatabaseException {
408 throw new UnsupportedOperationException();
411 protected ValueAccessor getValueAccessor(ReadGraph graph) throws DatabaseException {
412 if((property == null || property == NO_PROPERTY) && parentResource == null) return All.standardValueAccessor;
413 ValueAccessor accessor = property.valueAccessor;
414 if(accessor != null) return accessor;
416 System.err.println("No value accessor for " + getURI(graph));
417 return All.standardValueAccessor;
421 protected VariableMap getPossibleChildVariableMap(ReadGraph graph) throws DatabaseException {
422 if(represents == null) return All.standardPropertyDomainChildren;
423 Resource domainChildren = Layer0.getInstance(graph).domainChildren;
424 return graph.getPossibleRelatedValue2(represents, domainChildren,
425 new StandardGraphPropertyVariable(graph, this, domainChildren));
428 protected VariableMap getPossiblePropertyVariableMap(ReadGraph graph) throws DatabaseException {
429 if(property == null) return All.standardPropertyDomainProperties;
430 if(property.predicate == null) return null;
431 return graph.syncRequest(new PropertyVariableMapRequest(property.predicate), TransientCacheAsyncListener.<VariableMap>instance());
434 public Set<String> getClassifications(ReadGraph graph) throws DatabaseException {
435 return property.classifications;
439 public Map<String, Variable> collectDomainProperties(ReadGraph graph, String classification, Map<String, Variable> properties) throws DatabaseException {
441 VariableMap valueMap = getPossiblePropertyVariableMap(graph);
442 if(valueMap == null) return properties;
443 return valueMap.getVariables(graph, this, classification, properties);
447 public Collection<Variable> getProperties(ReadGraph graph, String classification) throws DatabaseException {
449 VariableMap valueMap = getPossiblePropertyVariableMap(graph);
450 if(valueMap == null) return Collections.emptyList();
451 Map<String,Variable> propertyMap = valueMap.getVariables(graph, this, classification, null);
452 if(propertyMap == null || propertyMap.isEmpty()) return Collections.emptyList();
453 else return propertyMap.values();