]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StandardGraphPropertyVariable.java
Implement equals/hashCode for PropertyInfo
[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.MissingVariableValueException;
25 import org.simantics.db.layer0.exception.PendingVariableException;
26 import org.simantics.db.layer0.function.All;
27 import org.simantics.db.layer0.request.PropertyInfo;
28 import org.simantics.db.layer0.request.PropertyInfoRequest;
29 import org.simantics.db.layer0.scl.SCLDatabaseException;
30 import org.simantics.db.layer0.util.Layer0Utils;
31 import org.simantics.layer0.Layer0;
32 import org.simantics.utils.Development;
33 import org.simantics.utils.datastructures.Pair;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 public class StandardGraphPropertyVariable extends AbstractPropertyVariable {
38
39     private static final Logger LOGGER = LoggerFactory.getLogger(StandardGraphPropertyVariable.class);
40
41     protected static final PropertyInfo NO_PROPERTY = new PropertyInfo(null, null, true,
42             false, false, Collections.<String> emptySet(), null, null, null, null, null, null,
43             Collections.<String, Pair<Resource, ChildReference>> emptyMap(),
44             null, false);
45
46         final public Variable parent;
47         final public Resource parentResource;
48         final public PropertyInfo property;
49         final public Resource represents;
50         
51         transient private int hash = 0;
52
53         public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, VariableNode node, Resource property) throws DatabaseException {
54                 this(graph, parent, node, (Resource)parent.getPossibleRepresents(graph), getPropertyInfo(graph, property));
55         }
56         
57         public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, VariableNode node, Resource parentResource, Resource property) throws DatabaseException {
58                 this(graph, parent, node, parentResource, getPropertyInfo(graph, property));
59         }
60
61         public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, Resource property) throws DatabaseException {
62         this(graph, parent, null, (Resource)parent.getPossibleRepresents(graph), getPropertyInfo(graph, property));
63     }
64
65     public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, Resource parentResource, PropertyInfo property) throws DatabaseException {
66         this(parent, null, parentResource, property, getPossibleRepresents(graph, parentResource, property.predicate));
67     }
68     
69     public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, VariableNode node, Resource parentResource, PropertyInfo property) throws DatabaseException {
70         this(parent, node, parentResource, property, getPossibleRepresents(graph, parentResource, property.predicate));
71     }
72
73     private static PropertyInfo getPropertyInfo(ReadGraph graph, Resource property) throws DatabaseException {
74             return property != null ? graph.syncRequest(new PropertyInfoRequest(property), TransientCacheAsyncListener.<PropertyInfo>instance()) : NO_PROPERTY;
75     }
76     
77     private static Resource getPossibleRepresents(ReadGraph graph, Resource parentResource, Resource predicate) throws DatabaseException {
78         if(parentResource == null || predicate == null) return null;
79         return graph.getPossibleObject(parentResource, predicate);
80     }
81     
82     public boolean isAsserted() {
83         return false;
84     }
85
86     public StandardGraphPropertyVariable(Variable parent, VariableNode node, Resource parentResource, PropertyInfo property, Resource represents) throws DatabaseException {
87         super(node);
88                 assert parent != null;
89                 this.parent = parent;
90                 this.property = property;
91                 this.parentResource = parentResource;
92                 this.represents = represents;
93         }
94
95         @Override
96         public String getName(ReadGraph graph) throws DatabaseException {
97             if(node != null) return node.support.manager.getName(node.node);
98                 return property.name;
99         }
100
101         @Override
102         public String getPossibleLabel(ReadGraph graph) throws DatabaseException {
103                 return graph.getPossibleRelatedValue2(property.predicate, graph.getService(Layer0.class).HasLabel, parent, Bindings.STRING);
104         }
105
106         @Override
107         public String getLabel(ReadGraph graph) throws DatabaseException {
108                 return graph.getRelatedValue2(property.predicate, graph.getService(Layer0.class).HasLabel, parent, Bindings.STRING);
109         }
110
111         @Override
112         public Variable getParent(ReadGraph graph) throws DatabaseException {
113                 return parent;
114         }
115         
116         @Override
117         public PropertyInfo getPropertyInfo(ReadGraph graph) throws DatabaseException {
118                 return property;
119         }
120
121         @SuppressWarnings("unchecked")
122         @Override
123         public <T> T getValue(ReadGraph graph) throws DatabaseException {
124                 
125                 if(Development.DEVELOPMENT) {
126                         if(Development.<Boolean>getProperty(DevelopmentKeys.L0_VALIDATION, Bindings.BOOLEAN)) {
127                                 String error = L0Validations.checkValueType(graph, parentResource, property.predicate);
128                                 if(error != null) {
129                                     LOGGER.error(error);
130                                         throw new ValidationException(error);
131                                 }
132                         }
133                 }
134                 
135                 return (T)getValueAccessor(graph).getValue(graph, this);
136                 
137         }
138
139         @SuppressWarnings("unchecked")
140         @Override
141         public <T> T getValue(ReadGraph graph, Binding binding) throws DatabaseException {
142                 // Fall back to the bindingless method, if the expected output is a Java object 
143                 if (binding instanceof ObjectVariantBinding)
144                         return getValue(graph);         
145
146                 if(Development.DEVELOPMENT) {
147                         if(Development.<Boolean>getProperty(DevelopmentKeys.L0_VALIDATION, Bindings.BOOLEAN)) {
148                                 String error = L0Validations.checkValueType(graph, parentResource, property.predicate);
149                                 if(error != null) {
150                                         LOGGER.error(error);
151                                         throw new ValidationException(error);
152                                 }
153                         }
154                 }
155         
156                 try {
157                         
158                         return (T) getValueAccessor(graph).getValue(graph, this, binding);
159                 } catch (SCLDatabaseException e) { // these can be thrown when compiling e.g. derived properties
160                         throw e;
161                 } catch (MissingVariableValueException | PendingVariableException e) {
162                         throw e;
163                 } catch (Throwable t) {
164                         throw new MissingVariableValueException(t);
165                 }
166                 
167         }
168         
169         @Override
170         public Resource getRepresents(ReadGraph graph) throws DatabaseException {
171                 if(represents == null)
172                         throw new InvalidVariableException("Variable is not represented by any resource (URI=" + getPossibleURI(graph) + ").");
173                 return represents;
174         }
175
176         @Override
177         public Resource getPossibleRepresents(ReadGraph graph) throws DatabaseException {
178                 return represents;
179         }
180
181         @Override
182         public void setValue(WriteGraph graph, Object value, Binding binding) throws DatabaseException {
183                 
184                 if(Development.DEVELOPMENT) {
185                         if(Development.<Boolean>getProperty(DevelopmentKeys.L0_VALIDATION, Bindings.BOOLEAN)) {
186                                 String error = L0Validations.checkValueType(graph, parentResource, property.predicate);
187                                 if(error != null) {
188                                         LOGGER.error(error);
189                                         throw new ValidationException(error);
190                                 }
191                         }
192                 }
193                 
194                 getValueAccessor(graph).setValue(graph, this, value, binding);
195                 
196         }
197         
198         @Override
199         public void setValue(WriteGraph graph, Object value) throws DatabaseException {
200                 
201                 if(Development.DEVELOPMENT) {
202                         if(Development.<Boolean>getProperty(DevelopmentKeys.L0_VALIDATION, Bindings.BOOLEAN)) {
203                                 String error = L0Validations.checkValueType(graph, parentResource, property.predicate);
204                                 if(error != null) {
205                                         LOGGER.error(error);
206                                         throw new ValidationException(error);
207                                 }
208                         }
209                 }
210                 
211                 getValueAccessor(graph).setValue(graph, this, value);
212                 
213         }
214
215         @Override
216         public Binding getDefaultBinding(ReadGraph graph) throws DatabaseException {
217                 return Layer0Utils.getDefaultBinding(graph, this);
218         }
219         
220         @Override
221         public Binding getPossibleDefaultBinding(ReadGraph graph) throws DatabaseException {
222                 return Layer0Utils.getPossibleDefaultBinding(graph, this);
223         }
224
225         @Override
226         public Datatype getDatatype(ReadGraph graph) throws DatabaseException {
227                 Datatype type;
228                 try {                   
229                         type = getValueAccessor(graph).getDatatype(graph, this);
230                 } catch (Throwable t) {
231                         throw new MissingVariableValueException(t);
232                 }
233                 
234                 if (type == null) {
235                         String uri = this.getPossibleURI(graph);
236                         if (uri != null)
237                                 throw new DatatypeNotFoundException("No data type for " + uri);
238                         else
239                                 throw new DatatypeNotFoundException("No data type for " + this.getIdentifier());
240                 }
241                 
242                 return type;
243                 
244         }
245         
246         @Override
247         public Datatype getPossibleDatatype(ReadGraph graph) throws DatabaseException {
248
249                 try {
250                         return getDatatype(graph);
251                 } catch (DatabaseException e) {
252                         return null;
253                 }
254                 
255         }
256         
257         @Override
258         public String getUnit(ReadGraph graph) throws DatabaseException {
259                 try {
260                         return Layer0Utils.getUnit(graph, this);
261                 } catch (DatabaseException e) {
262                         return null;
263                 }
264         }
265
266         @Override
267         public Resource getPropertyResource(ReadGraph graph) {
268                 return property.predicate;
269         }
270         
271         @Override
272         public Resource getContainerResource(ReadGraph graph) throws DatabaseException {
273                 return parentResource;
274         }
275
276         @Override
277         public Collection<Variable> getChildren(ReadGraph graph) throws DatabaseException {
278
279                 Map<String, Variable> result = new HashMap<String, Variable>();
280                 VariableMap map = getPossibleChildVariableMap(graph);
281                 if(map != null) map.getVariables(graph, this, result);
282                 return result.values();
283                 
284         }
285         
286         @Override
287         public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException {
288
289                 VariableMap map = getPossibleChildVariableMap(graph);
290                 if(map == null) return null;
291                 try {
292                         return map.getVariable(graph, this, name);
293                 } catch (DatabaseException e) {
294                         return null;
295                 }
296                 
297         }
298         
299         
300         @Override
301         protected Variable getPossibleDomainProperty(ReadGraph graph, String name) throws DatabaseException {
302
303                 VariableMap valueMap = getPossiblePropertyVariableMap(graph);
304                 if(valueMap == null) return null;
305                 try {
306                         return valueMap.getVariable(graph, this, name);
307                 } catch (DatabaseException e) {
308                         return null;
309                 } catch (Exception t) {
310                         LOGGER.error("getPossibleDomainProperty is implemented incorrectly, but returns null on Exception for backward compatibility. URI="+getURI(graph)+", name="+name+".", t);
311                         return null;
312                 }
313                 
314         }
315         
316         @Override
317         public Map<String, Variable> collectDomainProperties(ReadGraph graph, Map<String, Variable> properties) throws DatabaseException {
318
319                 VariableMap valueMap = getPossiblePropertyVariableMap(graph);
320                 if(valueMap == null) return properties;
321                 return valueMap.getVariables(graph, this, properties);
322                 
323         }
324         
325         @Override
326         public Variable getPredicate(ReadGraph graph) throws DatabaseException {
327                 return Variables.getVariable(graph, graph.getURI(property.predicate));
328         }
329         
330         @Override
331         public Resource getPredicateResource(ReadGraph graph) throws DatabaseException {
332                 return property.predicate;
333         }
334         
335         @Override
336         public Resource getPossiblePredicateResource(ReadGraph graph) throws DatabaseException {
337                 return property.predicate;
338         }
339
340         @Override
341         public int hashCode() {
342                 if(hash == 0) {
343                         final int prime = 31;
344                         int result = 1;
345             result = prime * result + (parent != null ? parent.hashCode() : 0);
346             result = prime * result + (node != null ? node.hashCode() : 0);
347             result = prime * result + (property.predicate != null ? property.predicate.hashCode() : 0);
348             result = prime * result + (parentResource != null ? parentResource.hashCode() : 0);
349             result = prime * result + (represents != null ? represents.hashCode() : 0);
350                         hash =result;
351                 }
352                 return hash;
353         }
354
355         @Override
356         public boolean equals(Object obj) {
357                 if (this == obj)
358                         return true;
359                 if (obj == null)
360                         return false;
361                 if (getClass() != obj.getClass())
362                         return false;
363                 StandardGraphPropertyVariable other = (StandardGraphPropertyVariable) obj;
364                 
365         if(node != null) {
366                 if(!node.equals(other.node)) return false;
367         } else if (other.node != null) return false;
368
369         if(property.predicate != null) {
370                 if(!property.predicate.equals(other.property.predicate)) return false;
371         } else if (other.property.predicate != null) return false;
372         
373         if(parentResource != null) {
374                 if(!parentResource.equals(other.parentResource)) return false;
375         } else if (other.parentResource != null) return false;
376
377         if(parent != null) {
378                 if(!parent.equals(other.parent)) return false;
379         } else if (other.parent != null) return false;
380
381         if(represents != null) {
382                 if(!represents.equals(other.represents)) return false;
383         } else if (other.represents != null) return false;
384
385         return true;
386                 
387         }
388
389         @Override
390         protected Variable getNameVariable(ReadGraph graph) throws DatabaseException {
391             throw new UnsupportedOperationException();
392         }
393         
394         protected ValueAccessor getValueAccessor(ReadGraph graph) throws DatabaseException {
395                 if((property == null || property == NO_PROPERTY) && parentResource == null) return All.standardValueAccessor;
396             ValueAccessor accessor = property.valueAccessor;
397             if(accessor != null) return accessor;
398             else {
399                 System.err.println("No value accessor for " + getURI(graph));
400                 return All.standardValueAccessor;
401             }
402         }
403
404         protected VariableMap getPossibleChildVariableMap(ReadGraph graph) throws DatabaseException {
405                 if(represents == null) return All.standardPropertyDomainChildren;
406             Resource domainChildren = Layer0.getInstance(graph).domainChildren;
407                 return graph.getPossibleRelatedValue2(represents, domainChildren, 
408                                 new StandardGraphPropertyVariable(graph, this, domainChildren));
409         }
410
411         protected VariableMap getPossiblePropertyVariableMap(ReadGraph graph) throws DatabaseException {
412         if(property == null) return All.standardPropertyDomainProperties;
413         if(property.predicate == null) return null;
414                 return graph.syncRequest(new PropertyVariableMapRequest(property.predicate), TransientCacheAsyncListener.<VariableMap>instance());
415         }
416         
417         public Set<String> getClassifications(ReadGraph graph) throws DatabaseException {
418                 return property.classifications;
419         }
420         
421         @Override
422     public Map<String, Variable> collectDomainProperties(ReadGraph graph, String classification, Map<String, Variable> properties) throws DatabaseException {
423         
424         VariableMap valueMap = getPossiblePropertyVariableMap(graph);
425                 if(valueMap == null) return properties;
426                 return valueMap.getVariables(graph, this, classification, properties);
427                 
428     }
429         
430     public Collection<Variable> getProperties(ReadGraph graph, String classification) throws DatabaseException {
431         
432         VariableMap valueMap = getPossiblePropertyVariableMap(graph);
433                 if(valueMap == null) return Collections.emptyList();
434                 Map<String,Variable> propertyMap = valueMap.getVariables(graph, this, classification, null);
435         if(propertyMap == null || propertyMap.isEmpty()) return Collections.emptyList();
436         else return propertyMap.values();
437         
438     }
439         
440 }