]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StandardGraphPropertyVariable.java
Fix handling of property variables with no predicate resource.
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / variable / StandardGraphPropertyVariable.java
1 package org.simantics.db.layer0.variable;
2
3 import java.util.Collection;
4 import java.util.Collections;
5 import java.util.HashMap;
6 import java.util.Map;
7 import java.util.Set;
8
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;
37
38 public class StandardGraphPropertyVariable extends AbstractPropertyVariable {
39
40     private static final Logger LOGGER = LoggerFactory.getLogger(StandardGraphPropertyVariable.class);
41
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(),
45             null, false);
46
47         final public Variable parent;
48         final public Resource parentResource;
49         final public PropertyInfo property;
50         final public Resource represents;
51         
52         transient private int hash = 0;
53
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));
56         }
57         
58         public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, VariableNode node, Resource parentResource, Resource property) throws DatabaseException {
59                 this(graph, parent, node, parentResource, getPropertyInfo(graph, property));
60         }
61
62         public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, Resource property) throws DatabaseException {
63         this(graph, parent, null, (Resource)parent.getPossibleRepresents(graph), getPropertyInfo(graph, property));
64     }
65
66     public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, Resource parentResource, PropertyInfo property) throws DatabaseException {
67         this(parent, null, parentResource, property, getPossibleRepresents(graph, parentResource, property.predicate));
68     }
69     
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));
72     }
73
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;
76     }
77     
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);
81     }
82     
83     public boolean isAsserted() {
84         return false;
85     }
86
87     public StandardGraphPropertyVariable(Variable parent, VariableNode node, Resource parentResource, PropertyInfo property, Resource represents) throws DatabaseException {
88         super(node);
89                 assert parent != null;
90                 this.parent = parent;
91                 this.property = property;
92                 this.parentResource = parentResource;
93                 this.represents = represents;
94         }
95
96         @Override
97         public String getName(ReadGraph graph) throws DatabaseException {
98             if(node != null) return node.support.manager.getName(node.node);
99                 return property.name;
100         }
101
102         @Override
103         public String getPossibleLabel(ReadGraph graph) throws DatabaseException {
104                 if (property.predicate == null)
105                         return null;
106                 return graph.getPossibleRelatedValue2(property.predicate, graph.getService(Layer0.class).HasLabel, parent, Bindings.STRING);
107         }
108
109         @Override
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);
114         }
115
116         @Override
117         public Variable getParent(ReadGraph graph) throws DatabaseException {
118                 return parent;
119         }
120         
121         @Override
122         public PropertyInfo getPropertyInfo(ReadGraph graph) throws DatabaseException {
123                 return property;
124         }
125
126         @SuppressWarnings("unchecked")
127         @Override
128         public <T> T getValue(ReadGraph graph) throws DatabaseException {
129                 
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);
134                                         if(error != null) {
135                                             LOGGER.error(error);
136                                                 throw new ValidationException(error);
137                                         }
138                                 }
139                         }
140                 }
141                 
142                 return (T)getValueAccessor(graph).getValue(graph, this);
143                 
144         }
145
146         @SuppressWarnings("unchecked")
147         @Override
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);         
152
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);
157                                         if(error != null) {
158                                                 LOGGER.error(error);
159                                                 throw new ValidationException(error);
160                                         }
161                                 }
162                         }
163                 }
164         
165                 try {
166                         
167                         return (T) getValueAccessor(graph).getValue(graph, this, binding);
168                 } catch (SCLDatabaseException e) { // these can be thrown when compiling e.g. derived properties
169                         throw e;
170                 } catch (MissingVariableValueException | PendingVariableException e) {
171                         throw e;
172                 } catch (Throwable t) {
173                         throw new MissingVariableValueException(t);
174                 }
175                 
176         }
177         
178         @Override
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) + ").");
182                 return represents;
183         }
184
185         @Override
186         public Resource getPossibleRepresents(ReadGraph graph) throws DatabaseException {
187                 return represents;
188         }
189
190         @Override
191         public void setValue(WriteGraph graph, Object value, Binding binding) throws DatabaseException {
192                 
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);
197                                         if(error != null) {
198                                                 LOGGER.error(error);
199                                                 throw new ValidationException(error);
200                                         }
201                                 }
202                         }
203                 }
204                 
205                 getValueAccessor(graph).setValue(graph, this, value, binding);
206                 
207         }
208         
209         @Override
210         public void setValue(WriteGraph graph, Object value) throws DatabaseException {
211                 
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);
216                                         if(error != null) {
217                                                 LOGGER.error(error);
218                                                 throw new ValidationException(error);
219                                         }
220                                 }
221                         }
222                 }
223                 
224                 getValueAccessor(graph).setValue(graph, this, value);
225                 
226         }
227
228         @Override
229         public Binding getDefaultBinding(ReadGraph graph) throws DatabaseException {
230                 return Layer0Utils.getDefaultBinding(graph, this);
231         }
232         
233         @Override
234         public Binding getPossibleDefaultBinding(ReadGraph graph) throws DatabaseException {
235                 return Layer0Utils.getPossibleDefaultBinding(graph, this);
236         }
237
238         @Override
239         public Datatype getDatatype(ReadGraph graph) throws DatabaseException {
240                 Datatype type;
241                 try {                   
242                         type = getValueAccessor(graph).getDatatype(graph, this);
243                 } catch (Throwable t) {
244                         throw new MissingVariableValueException(t);
245                 }
246                 
247                 if (type == null) {
248                         String uri = this.getPossibleURI(graph);
249                         if (uri != null)
250                                 throw new DatatypeNotFoundException("No data type for " + uri);
251                         else
252                                 throw new DatatypeNotFoundException("No data type for " + this.getIdentifier());
253                 }
254                 
255                 return type;
256                 
257         }
258         
259         @Override
260         public Datatype getPossibleDatatype(ReadGraph graph) throws DatabaseException {
261
262                 try {
263                         return getDatatype(graph);
264                 } catch (DatabaseException e) {
265                         return null;
266                 }
267                 
268         }
269         
270         @Override
271         public String getUnit(ReadGraph graph) throws DatabaseException {
272                 try {
273                         return Layer0Utils.getUnit(graph, this);
274                 } catch (DatabaseException e) {
275                         return null;
276                 }
277         }
278
279         @Override
280         public Resource getPropertyResource(ReadGraph graph) {
281                 return property.predicate;
282         }
283         
284         @Override
285         public Resource getContainerResource(ReadGraph graph) throws DatabaseException {
286                 return parentResource;
287         }
288
289         @Override
290         public Collection<Variable> getChildren(ReadGraph graph) throws DatabaseException {
291
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();
296                 
297         }
298         
299         @Override
300         public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException {
301
302                 VariableMap map = getPossibleChildVariableMap(graph);
303                 if(map == null) return null;
304                 try {
305                         return map.getVariable(graph, this, name);
306                 } catch (DatabaseException e) {
307                         return null;
308                 }
309                 
310         }
311         
312         
313         @Override
314         protected Variable getPossibleDomainProperty(ReadGraph graph, String name) throws DatabaseException {
315
316                 VariableMap valueMap = getPossiblePropertyVariableMap(graph);
317                 if(valueMap == null) return null;
318                 try {
319                         return valueMap.getVariable(graph, this, name);
320                 } catch (DatabaseException e) {
321                         return null;
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);
324                         return null;
325                 }
326                 
327         }
328         
329         @Override
330         public Map<String, Variable> collectDomainProperties(ReadGraph graph, Map<String, Variable> properties) throws DatabaseException {
331
332                 VariableMap valueMap = getPossiblePropertyVariableMap(graph);
333                 if(valueMap == null) return properties;
334                 return valueMap.getVariables(graph, this, properties);
335                 
336         }
337         
338         @Override
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));
343         }
344         
345         @Override
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;
350         }
351         
352         @Override
353         public Resource getPossiblePredicateResource(ReadGraph graph) throws DatabaseException {
354                 return property.predicate;
355         }
356
357         @Override
358         public int hashCode() {
359                 if(hash == 0) {
360                         final int prime = 31;
361                         int result = 1;
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);
367                         hash =result;
368                 }
369                 return hash;
370         }
371
372         @Override
373         public boolean equals(Object obj) {
374                 if (this == obj)
375                         return true;
376                 if (obj == null)
377                         return false;
378                 if (getClass() != obj.getClass())
379                         return false;
380                 StandardGraphPropertyVariable other = (StandardGraphPropertyVariable) obj;
381                 
382         if(node != null) {
383                 if(!node.equals(other.node)) return false;
384         } else if (other.node != null) return false;
385
386         if(property.predicate != null) {
387                 if(!property.predicate.equals(other.property.predicate)) return false;
388         } else if (other.property.predicate != null) return false;
389         
390         if(parentResource != null) {
391                 if(!parentResource.equals(other.parentResource)) return false;
392         } else if (other.parentResource != null) return false;
393
394         if(parent != null) {
395                 if(!parent.equals(other.parent)) return false;
396         } else if (other.parent != null) return false;
397
398         if(represents != null) {
399                 if(!represents.equals(other.represents)) return false;
400         } else if (other.represents != null) return false;
401
402         return true;
403                 
404         }
405
406         @Override
407         protected Variable getNameVariable(ReadGraph graph) throws DatabaseException {
408             throw new UnsupportedOperationException();
409         }
410         
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;
415             else {
416                 System.err.println("No value accessor for " + getURI(graph));
417                 return All.standardValueAccessor;
418             }
419         }
420
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));
426         }
427
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());
432         }
433         
434         public Set<String> getClassifications(ReadGraph graph) throws DatabaseException {
435                 return property.classifications;
436         }
437         
438         @Override
439     public Map<String, Variable> collectDomainProperties(ReadGraph graph, String classification, Map<String, Variable> properties) throws DatabaseException {
440         
441         VariableMap valueMap = getPossiblePropertyVariableMap(graph);
442                 if(valueMap == null) return properties;
443                 return valueMap.getVariables(graph, this, classification, properties);
444                 
445     }
446         
447     public Collection<Variable> getProperties(ReadGraph graph, String classification) throws DatabaseException {
448         
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();
454         
455     }
456         
457 }