]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/AbstractVariable.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / variable / AbstractVariable.java
1 package org.simantics.db.layer0.variable;\r
2 \r
3 import gnu.trove.map.hash.THashMap;\r
4 \r
5 import java.util.Collection;\r
6 import java.util.Collections;\r
7 import java.util.HashMap;\r
8 import java.util.Map;\r
9 import java.util.Set;\r
10 \r
11 import org.simantics.databoard.Bindings;\r
12 import org.simantics.databoard.Databoard;\r
13 import org.simantics.databoard.binding.Binding;\r
14 import org.simantics.databoard.binding.StringBinding;\r
15 import org.simantics.databoard.binding.error.BindingConstructionException;\r
16 import org.simantics.databoard.binding.error.BindingException;\r
17 import org.simantics.databoard.binding.mutable.Variant;\r
18 import org.simantics.databoard.type.Datatype;\r
19 import org.simantics.databoard.util.URIStringUtils;\r
20 import org.simantics.datatypes.literal.GUID;\r
21 import org.simantics.db.ReadGraph;\r
22 import org.simantics.db.Resource;\r
23 import org.simantics.db.WriteGraph;\r
24 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;\r
25 import org.simantics.db.common.request.PossibleIndexRoot;\r
26 import org.simantics.db.common.request.PropertyMapOfResource;\r
27 import org.simantics.db.common.utils.NameUtils;\r
28 import org.simantics.db.exception.AdaptionException;\r
29 import org.simantics.db.exception.DatabaseException;\r
30 import org.simantics.db.layer0.exception.InvalidVariableException;\r
31 import org.simantics.db.layer0.exception.MissingVariableException;\r
32 import org.simantics.db.layer0.exception.MissingVariableValueException;\r
33 import org.simantics.db.layer0.request.PossibleResource;\r
34 import org.simantics.db.layer0.request.PropertyInfo;\r
35 import org.simantics.db.layer0.request.VariableRVIRequest;\r
36 import org.simantics.db.layer0.variable.RVI.GuidRVIPart;\r
37 import org.simantics.db.layer0.variable.RVI.RVIPart;\r
38 import org.simantics.db.layer0.variable.RVI.ResourceRVIPart;\r
39 import org.simantics.db.layer0.variable.RVI.StringRVIPart;\r
40 import org.simantics.db.layer0.variable.Variables.Role;\r
41 import org.simantics.layer0.Layer0;\r
42 \r
43 /**\r
44  * Abstract implementation of Variable -interface.\r
45  * \r
46  * @author Hannu Niemistö\r
47  */\r
48 public abstract class AbstractVariable implements Variable {\r
49 \r
50     @SuppressWarnings("rawtypes")\r
51     final public VariableNode node;\r
52 \r
53     public AbstractVariable(@SuppressWarnings("rawtypes") VariableNode node) {\r
54         this.node = node;\r
55     }\r
56 \r
57     /**\r
58      * Returns a variable that is not one of the standard properties listed\r
59      * in <a href="https://www.simantics.org/wiki/index.php/Org.simantics.db.layer0.variable.Variable#Standard_required_properties">specification</a>.\r
60      */\r
61     protected abstract Variable getPossibleDomainProperty(ReadGraph graph, String name) throws DatabaseException;\r
62     public abstract Variable getPossibleExtraProperty(ReadGraph graph, String name) throws DatabaseException;\r
63     public abstract Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException;\r
64         \r
65     public abstract void collectExtraProperties(ReadGraph graph, Map<String, Variable> properties) throws DatabaseException;\r
66     public abstract Map<String, Variable> collectDomainProperties(ReadGraph graph, Map<String, Variable> map) throws DatabaseException;\r
67     public abstract Collection<Variable> getChildren(ReadGraph graph) throws DatabaseException;\r
68     \r
69     public abstract <T> T getValue(ReadGraph graph) throws DatabaseException;\r
70     public abstract <T> T getValue(ReadGraph graph, Binding binding) throws DatabaseException;\r
71 \r
72     public abstract void setValue(WriteGraph graph, Object value, Binding binding) throws DatabaseException;\r
73     public abstract String getName(ReadGraph graph) throws DatabaseException;\r
74     //public abstract Object getSerialized(ReadGraph graph) throws DatabaseException;\r
75     public abstract Variable getParent(ReadGraph graph) throws DatabaseException;\r
76     public abstract Role getRole(ReadGraph graph) throws DatabaseException;\r
77     public abstract Resource getRepresents(ReadGraph graph) throws DatabaseException;\r
78     \r
79     public abstract Set<String> getClassifications(ReadGraph graph) throws DatabaseException;\r
80      \r
81     @Override\r
82     public PropertyInfo getPropertyInfo(ReadGraph graph) throws DatabaseException {\r
83         throw new DatabaseException("PropertyInfo is not available");\r
84     }\r
85     \r
86     @Override\r
87     public Resource getIndexRoot(ReadGraph graph) throws DatabaseException {\r
88         Resource represents = getPossibleRepresents(graph);\r
89         if(represents != null) return graph.syncRequest(new PossibleIndexRoot(represents));\r
90         Variable parent = getParent(graph);\r
91         if(parent == null) return null;\r
92         return parent.getIndexRoot(graph);\r
93     }\r
94     \r
95     public void validate(ReadGraph graph) throws DatabaseException {\r
96     }\r
97 \r
98     public String getIdentifier() {\r
99         return getClass().getSimpleName();\r
100     }\r
101     \r
102     \r
103     @Override\r
104     public Role getPossibleRole(ReadGraph graph) throws DatabaseException {\r
105         try {\r
106                 return getRole(graph);\r
107         } catch (DatabaseException e) {\r
108                 return null;\r
109         }\r
110     }\r
111     \r
112     protected Variable resolveChild(ReadGraph graph, Resource resource) throws DatabaseException {\r
113         String rName = graph.getRelatedValue(resource, Layer0.getInstance(graph).HasName, Bindings.STRING);\r
114         for(Variable child : browseChildren(graph)) {\r
115                 String name = child.getPossiblePropertyValue(graph, Variables.NAME, Bindings.STRING);\r
116                 if(rName.equals(name)) return child;\r
117         }\r
118         throw new DatabaseException("Could not resolve child " + resource);\r
119     }\r
120     \r
121     protected Variable resolveChild(ReadGraph graph, GuidRVIPart part) throws DatabaseException {\r
122         return StandardRVIResolver.resolveChildDefault(graph, this, part);\r
123     }\r
124     \r
125     protected Variable resolveProperty(ReadGraph graph, Resource resource) throws DatabaseException {\r
126         String rName = graph.getRelatedValue(resource, Layer0.getInstance(graph).HasName, Bindings.STRING);\r
127         for(Variable child : browseProperties(graph)) {\r
128                 String name = child.getPossiblePropertyValue(graph, Variables.NAME, Bindings.STRING);\r
129                 if(rName.equals(name)) return child;\r
130         }\r
131         throw new DatabaseException("Could not resolve child " + resource);\r
132     }\r
133 \r
134     protected Variable resolveProperty(ReadGraph graph, GuidRVIPart part) throws DatabaseException {\r
135         return StandardRVIResolver.resolvePropertyDefault(graph, this, part);\r
136     }\r
137 \r
138     protected Variable resolvePossibleChild(ReadGraph graph, Resource resource) throws DatabaseException {\r
139         String rName = graph.getRelatedValue(resource, Layer0.getInstance(graph).HasName, Bindings.STRING);\r
140         for(Variable child : browseChildren(graph)) {\r
141             String name = child.getPossiblePropertyValue(graph, Variables.NAME, Bindings.STRING);\r
142             if(rName.equals(name)) return child;\r
143         }\r
144         return null;\r
145     }\r
146     \r
147     protected Variable resolvePossibleChild(ReadGraph graph, GuidRVIPart part) throws DatabaseException {\r
148                 Layer0 L0 = Layer0.getInstance(graph);\r
149         for(Variable child : browseChildren(graph)) {\r
150                 GUID id = child.getPossiblePropertyValue(graph, L0.identifier, GUID.BINDING);\r
151                 if(id != null) {\r
152                         if(id.mostSignificant == part.mostSignificant && id.leastSignificant == part.leastSignificant)\r
153                                 return child;\r
154                 }\r
155         }\r
156         return null;\r
157     }\r
158 \r
159     protected Variable resolvePossibleProperty(ReadGraph graph, Resource resource) throws DatabaseException {\r
160         String rName = graph.getRelatedValue(resource, Layer0.getInstance(graph).HasName, Bindings.STRING);\r
161         for(Variable child : browseProperties(graph)) {\r
162             String name = child.getPossiblePropertyValue(graph, Variables.NAME, Bindings.STRING);\r
163             if(rName.equals(name)) return child;\r
164         }\r
165         return null;\r
166     }\r
167 \r
168     protected Variable resolvePossibleProperty(ReadGraph graph, GuidRVIPart part) throws DatabaseException {\r
169                 Layer0 L0 = Layer0.getInstance(graph);\r
170         for(Variable child : browseProperties(graph)) {\r
171                 GUID id = child.getPossiblePropertyValue(graph, L0.identifier, GUID.BINDING);\r
172                 if(id != null) {\r
173                         if(id.mostSignificant == part.mostSignificant && id.leastSignificant == part.leastSignificant)\r
174                                 return child;\r
175                 }\r
176         }\r
177         return null;\r
178     }\r
179 \r
180     public String getLabel(ReadGraph graph) throws DatabaseException { \r
181         return getName(graph);\r
182     }\r
183     \r
184     public String getPossibleLabel(ReadGraph graph) throws DatabaseException {\r
185         Resource represents = getPossibleRepresents(graph);\r
186         if(represents == null) return null;\r
187                 return graph.getPossibleRelatedValue2(represents, graph.getService(Layer0.class).HasLabel, getParent(graph), Bindings.STRING);\r
188     }\r
189 \r
190     public Resource getType(ReadGraph graph) throws DatabaseException {\r
191         \r
192         Resource resource = getPossibleRepresents(graph);\r
193         if(resource == null) {\r
194                 String uri = getPossiblePropertyValue(graph, "typeURI");\r
195                 if(uri != null) return graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri), TransientCacheAsyncListener.<Resource>instance());\r
196             throw new DatabaseException("No type for " + getURI(graph));\r
197         }\r
198         return graph.getSingleType(resource);\r
199         \r
200     }\r
201     \r
202     public RVIPart getRVIPart(ReadGraph graph) throws DatabaseException {\r
203         throw new UnsupportedOperationException();\r
204     }\r
205 \r
206     @Override\r
207     public RVI getRVI(ReadGraph graph) throws DatabaseException {\r
208         Databoard databoard = graph.getService( Databoard.class );\r
209         Binding rviBinding = databoard.getBindingUnchecked( RVI.class );\r
210         if(Variables.isContext(graph, this)) {\r
211                 return RVI.empty( rviBinding );\r
212         } else {\r
213                 Variable parent = getParent(graph);\r
214                 if (parent == null)\r
215                         // TODO: consider using a more suitable exception here to better convey the situation.\r
216                         throw new MissingVariableException("no parent for variable " + this + " (URI=" + getPossibleURI(graph) + ")");\r
217                 RVI base = graph.syncRequest(new VariableRVIRequest(parent));\r
218                 RVIPart part = getRVIPart(graph);\r
219                 return new RVIBuilder(base).append(part).toRVI();\r
220         }\r
221     }\r
222     \r
223     protected Variable getDomainProperty(ReadGraph graph, String name) throws DatabaseException {\r
224         Variable property = getPossibleDomainProperty(graph, name);\r
225         if(property == null)\r
226             throw new MissingVariableException(getIdentifier() + ": Didn't find property " + name + ".");\r
227         return property;\r
228     }\r
229     \r
230     protected void addProperty(Map<String, Variable> properties, String name, Object value, Binding binding) {\r
231         if(value != null) {\r
232             properties.put(name, new ConstantPropertyVariable(this, name, value, binding));\r
233         }\r
234     }\r
235 \r
236     protected Variable getNameVariable(ReadGraph graph) throws DatabaseException {\r
237         return new ConstantPropertyVariable(this, Variables.NAME, getName(graph), Bindings.STRING);\r
238     }\r
239 \r
240     protected Variable getLabelVariable(ReadGraph graph) throws DatabaseException {\r
241         return new ConstantPropertyVariable(this, Variables.LABEL, getPossibleLabel(graph), Bindings.STRING);\r
242     }\r
243 \r
244     final public Collection<Variable> browseProperties(ReadGraph graph) throws DatabaseException {\r
245         return getProperties(graph);\r
246     }\r
247 \r
248     private Map<String, Variable> getPropertyMap(ReadGraph graph, String classification) throws DatabaseException {\r
249         return collectDomainProperties(graph, classification, null);\r
250     }\r
251 \r
252     final static class PropertyMap extends THashMap<String,Variable> {\r
253         \r
254         final private Variable variable;\r
255         \r
256         PropertyMap(Variable variable) {\r
257                 this.variable = variable;\r
258         }\r
259 \r
260         private Variable getTypeVariable() {\r
261                 \r
262                 return new AbstractConstantPropertyVariable(variable, Variables.TYPE, null) {\r
263 \r
264                                 @SuppressWarnings("unchecked")\r
265                                 @Override\r
266                                 public <T> T getValue(ReadGraph graph) throws DatabaseException {\r
267                                         Resource represents = parent.getRepresents(graph);\r
268                                         if(represents == null) return null;\r
269                                         return (T)graph.getPossibleType(represents, Layer0.getInstance(graph).Entity);\r
270                                 }\r
271 \r
272                                 @Override\r
273                                 public <T> T getValue(ReadGraph graph, Binding binding) throws DatabaseException {\r
274                                         return getValue(graph);\r
275                                 }\r
276                         \r
277                 };\r
278         }\r
279 \r
280         private Variable getURIVariable() {\r
281                 \r
282                 return new AbstractConstantPropertyVariable(variable, Variables.URI, null) {\r
283 \r
284                                 @SuppressWarnings("unchecked")\r
285                                 @Override\r
286                                 public <T> T getValue(ReadGraph graph) throws DatabaseException {\r
287                                         return (T)variable.getURI(graph);\r
288                                 }\r
289 \r
290                                 @Override\r
291                                 public <T> T getValue(ReadGraph graph, Binding binding) throws DatabaseException {\r
292                                         return getValue(graph);\r
293                                 }\r
294                         \r
295                 };\r
296         }\r
297 \r
298         public Variable get(Object key) {\r
299                 Variable result = super.get(key);\r
300                 if(result != null) return result;\r
301                 \r
302                 if(Variables.TYPE.equals(key)) return getTypeVariable();\r
303                 else if(Variables.URI.equals(key)) return getURIVariable();\r
304                 \r
305                         return variable;\r
306                 }\r
307         \r
308     }\r
309     \r
310     private Map<String, Variable> getPropertyMap(ReadGraph graph) throws DatabaseException {\r
311         PropertyMap properties = new PropertyMap(this);\r
312 //        Map<String, Variable> properties = new HashMap<String, Variable>();\r
313 //        try {\r
314 //            properties.put(Variables.NAME, getNameVariable(graph));\r
315 //        } catch (DatabaseException e) {\r
316 //            // A variable that has no name doesn't exist by definition.\r
317 //            // Therefore it can't have any properties.\r
318 //            return Collections.emptyMap();\r
319 //        }\r
320 //        try {\r
321 //            Variable labelVariable = getLabelVariable(graph);\r
322 //            if(labelVariable != null) properties.put(Variables.LABEL, getLabelVariable(graph));\r
323 //        } catch (DatabaseException e) {\r
324 //            // Label not absolutely mandatory.\r
325 //        }\r
326 //        addProperty(properties, Variables.TYPE, getPossibleType(graph), null);\r
327 //        addProperty(properties, Variables.URI, getPossibleURI(graph), Bindings.STRING);\r
328         //addProperty(properties, Variables.SERIALISED, getSerialized(graph), Bindings.STRING);\r
329         //addProperty(properties, Variables.PARENT, getParent(graph), null);\r
330 //        addProperty(properties, Variables.ROLE, getRole(graph), Bindings.STRING);\r
331 //        addProperty(properties, Variables.REPRESENTS, getPossibleRepresents(graph), null);\r
332         collectExtraProperties(graph, properties);\r
333         collectDomainProperties(graph, properties);\r
334         return properties;\r
335     }\r
336     \r
337     @Override\r
338     public Collection<Variable> getProperties(ReadGraph graph) throws DatabaseException {\r
339         return getPropertyMap(graph).values();\r
340     }\r
341     \r
342     public Collection<Variable> getProperties(ReadGraph graph, String classification) throws DatabaseException {\r
343         Map<String,Variable> propertyMap = getPropertyMap(graph, classification);\r
344         if(propertyMap == null) return Collections.emptyList();\r
345         else return propertyMap.values();\r
346     }\r
347 \r
348     @Override\r
349     public Collection<Variable> getProperties(ReadGraph graph, Resource property) throws DatabaseException {\r
350         return getProperties(graph, uri(graph, property));\r
351     }\r
352 \r
353     final public Collection<Variable> browseChildren(ReadGraph graph) throws DatabaseException {\r
354         return getChildren(graph);\r
355     }\r
356     \r
357     @Override\r
358     public Variable getPossibleProperty(ReadGraph graph, String name)\r
359             throws DatabaseException {\r
360         if(Variables.NAME.equals(name)) {\r
361                 return getNameVariable(graph);\r
362         }\r
363         if(Variables.LABEL.equals(name)) {\r
364                 return getLabelVariable(graph);\r
365         }\r
366         if(Variables.TYPE.equals(name)) {\r
367             Object value = getPossibleType(graph);\r
368             if(value != null)\r
369                 return new ConstantPropertyVariable(this, name, value, null);\r
370         }\r
371         if(Variables.URI.equals(name)) {\r
372             // TODO: getPossibleURI or getURI?\r
373             Object value = getURI(graph);\r
374             if(value != null)\r
375                 return new ConstantPropertyVariable(this, name, value, Bindings.STRING);\r
376         }\r
377 //        if(Variables.SERIALISED.equals(name)) {\r
378 //            Object value = getSerialized(graph);\r
379 //            if(value != null)\r
380 //                return new ConstantPropertyVariable(this, name, value, Bindings.STRING);\r
381 //        }\r
382         /*if(Variables.PARENT.equals(name)) {\r
383             Object value = getParent(graph);\r
384             if(value != null)\r
385                 return new ConstantPropertyVariable(this, name, value, null);\r
386         }*/\r
387 //        if(Variables.ROLE.equals(name)) {\r
388 //            Object value = getRole(graph);\r
389 //            if(value != null)\r
390 //                return new ConstantPropertyVariable(this, name, value, null);\r
391 //        }\r
392 //        if(Variables.REPRESENTS.equals(name)) {\r
393 //            Object value = getRepresents(graph);\r
394 //            if(value != null)\r
395 //                return new ConstantPropertyVariable(this, name, value, null);\r
396 //        }\r
397         Variable extra = getPossibleExtraProperty(graph, name);\r
398         if(extra != null) return extra;\r
399         return getPossibleDomainProperty(graph, name);\r
400     }\r
401     \r
402     @Override\r
403     public Variable getPossibleProperty(ReadGraph graph, Resource property) throws DatabaseException {\r
404         return getPossibleProperty(graph, name(graph, property));\r
405     }\r
406 \r
407     @SuppressWarnings("unchecked")\r
408     protected <T> T checkNull(ReadGraph graph, Object value) throws DatabaseException {\r
409         if(value == null)\r
410             throw new MissingVariableValueException(getClass().getSimpleName() + ": Didn't find value for " + getPossibleURI(graph));\r
411         return (T)value;\r
412     }\r
413 \r
414     private String name(ReadGraph graph, Resource property) throws DatabaseException {\r
415         return graph.getRelatedValue(property, Layer0.getInstance(graph).HasName, Bindings.STRING);\r
416     }\r
417     \r
418     private String uri(ReadGraph graph, Resource property) throws DatabaseException {\r
419         return graph.getURI(property);\r
420     }\r
421 \r
422     @Override\r
423     public <T> T getPropertyValue(ReadGraph graph, String name) throws DatabaseException {\r
424         if(Variables.LABEL.equals(name)) return checkNull(graph, getLabel(graph));\r
425         Variable result = getDomainProperty(graph, name);\r
426         if(result != null) return result.getValue(graph);\r
427         if(Variables.NAME.equals(name)) return checkNull(graph, getName(graph));\r
428         if(Variables.TYPE.equals(name)) return checkNull(graph, getPossibleType(graph));\r
429         if(Variables.URI.equals(name)) return checkNull(graph, getURI(graph));\r
430 //      if(Variables.SERIALISED.equals(name)) return checkNull(graph, getSerialized(graph));\r
431 //      if(Variables.ROLE.equals(name)) return checkNull(graph, getRole(graph));\r
432 //      if(Variables.REPRESENTS.equals(name)) return checkNull(graph, getRepresents(graph));\r
433         Variable extra = getPossibleExtraProperty(graph, name);\r
434         if(extra != null) return extra.getValue(graph);\r
435         return null;\r
436     }    \r
437     \r
438     @Override\r
439     public <T> T getPropertyValue(ReadGraph graph, Resource property) throws DatabaseException {\r
440         return getPropertyValue(graph, name(graph, property));\r
441     }\r
442     \r
443     @SuppressWarnings("unchecked")\r
444     @Override\r
445     public <T> T getPossiblePropertyValue(ReadGraph graph, String name)\r
446             throws DatabaseException {\r
447         \r
448         Variable property = getPossibleDomainProperty(graph, name);\r
449         if(property != null) return property.getPossibleValue(graph);\r
450         \r
451         if(Variables.NAME.equals(name)) return (T)getName(graph);\r
452         if(Variables.LABEL.equals(name)) return (T)getLabel(graph);\r
453         if(Variables.TYPE.equals(name)) return (T)getPossibleType(graph);\r
454         if(Variables.URI.equals(name)) return (T)getURI(graph);\r
455 //        if(Variables.SERIALISED.equals(name)) return (T)getSerialized(graph);\r
456 //        if(Variables.ROLE.equals(name)) return (T)getRole(graph);\r
457 //        if(Variables.REPRESENTS.equals(name)) return (T)getRepresents(graph);\r
458         \r
459         Variable extra = getPossibleExtraProperty(graph, name);\r
460         if(extra != null) return extra.getPossibleValue(graph);\r
461         \r
462         return null;\r
463         \r
464     }\r
465 \r
466     @Override\r
467     public <T> T getPossiblePropertyValue(ReadGraph graph, Resource property) throws DatabaseException {\r
468         return getPossiblePropertyValue(graph, name(graph, property));\r
469     }\r
470 \r
471     @SuppressWarnings("unchecked")\r
472     @Override\r
473     public <T> T getPropertyValue(ReadGraph graph, String name, Binding binding)\r
474             throws DatabaseException {\r
475         if(binding instanceof StringBinding) {\r
476             StringBinding sb = (StringBinding)binding;\r
477             try {\r
478                 if(Variables.NAME.equals(name)) return (T)sb.create((String)checkNull(graph, getName(graph)));\r
479                 if(Variables.LABEL.equals(name)) return (T)sb.create((String)checkNull(graph, getLabel(graph)));\r
480                 if(Variables.URI.equals(name)) return (T)sb.create((String)checkNull(graph, getURI(graph)));\r
481 //                if(Variables.SERIALISED.equals(name)) return (T)sb.create((String)checkNull(graph, getSerialized(graph)));\r
482             } catch(BindingException e) {\r
483                 throw new DatabaseException(e);\r
484             }\r
485         }\r
486         Variable property = getPossibleExtraProperty(graph, name);\r
487         if(property != null)\r
488             return property.getValue(graph, binding);\r
489         property = getPossibleDomainProperty(graph, name);\r
490         if(property == null)\r
491             throw new MissingVariableException("Didn't find property " + name + " for " + this + ".");\r
492         return property.getValue(graph, binding);\r
493     }\r
494 \r
495     @Override\r
496     public <T> T getPropertyValue(ReadGraph graph, Resource property, Binding binding) throws DatabaseException {\r
497         return getPropertyValue(graph, name(graph, property), binding);\r
498     }\r
499 \r
500     @SuppressWarnings("unchecked")\r
501     @Override\r
502     public <T> T getPossiblePropertyValue(ReadGraph graph, String name,\r
503             Binding binding) throws DatabaseException {\r
504         if(binding instanceof StringBinding) {\r
505             StringBinding sb = (StringBinding)binding;\r
506             try {\r
507                 if(Variables.NAME.equals(name)) return (T)sb.create((String)getName(graph));\r
508                 if(Variables.LABEL.equals(name)) return (T)sb.create((String)getLabel(graph));\r
509                 if(Variables.URI.equals(name)) return (T)sb.create((String)getURI(graph));\r
510 //                if(Variables.SERIALISED.equals(name)) return (T)sb.create((String)getSerialized(graph));\r
511             } catch(BindingException e) {\r
512                 throw new DatabaseException(e);\r
513             }\r
514         }\r
515         Variable property = getPossibleExtraProperty(graph, name);\r
516         if(property != null)\r
517             return property.getPossibleValue(graph, binding);\r
518         property = getPossibleDomainProperty(graph, name);\r
519         if(property == null)\r
520             return null;\r
521         return property.getPossibleValue(graph, binding);\r
522     }\r
523 \r
524     @Override\r
525     public <T> T getPossiblePropertyValue(ReadGraph graph, Resource property, Binding binding) throws DatabaseException {\r
526         return getPossiblePropertyValue(graph, name(graph, property), binding);\r
527     }\r
528 \r
529     @Override\r
530     public void setValue(WriteGraph graph, Object value) throws DatabaseException {\r
531         try {\r
532                         setValue(graph, value, Bindings.getBinding(value.getClass()));\r
533                 } catch (BindingConstructionException e) {\r
534                         throw new DatabaseException(e);\r
535                 }\r
536     }\r
537     \r
538     @Override\r
539     public void setPropertyValue(WriteGraph graph, String name, Object value) throws DatabaseException {\r
540         getProperty(graph, name).setValue(graph, value);\r
541     }\r
542 \r
543     @Override\r
544     public void setPropertyValue(WriteGraph graph, Resource property, Object value) throws DatabaseException {\r
545         setPropertyValue(graph, name(graph, property), value);\r
546     }\r
547 \r
548     @Override\r
549     public void setPropertyValue(WriteGraph graph, String name, Object value,\r
550             Binding binding) throws DatabaseException {\r
551         getProperty(graph, name).setValue(graph, value, binding);\r
552     }\r
553 \r
554     @Override\r
555     public void setPropertyValue(WriteGraph graph, Resource property, Object value, Binding binding) throws DatabaseException {\r
556         setPropertyValue(graph, name(graph, property), value, binding);\r
557     }\r
558 \r
559     @Override\r
560     public Variable getChild(ReadGraph graph, String name)\r
561             throws DatabaseException {\r
562         Variable child = getPossibleChild(graph, name);\r
563         if(child == null)\r
564             throw new MissingVariableException(getURI(graph) + ": didn't find child " + name + " for " + getIdentifier() + ".");\r
565         return child;\r
566     }    \r
567 \r
568     @Override\r
569     public Variable getProperty(ReadGraph graph, String name)  throws DatabaseException {\r
570         Variable result = getPossibleProperty(graph, name);\r
571         if(result == null)\r
572             throw new MissingVariableException(getClass().getSimpleName() + ": Didn't find property " + name + " for " + getPossibleURI(graph) + ".");\r
573         return result;\r
574     }\r
575     \r
576     @Override\r
577     public Variable getProperty(ReadGraph graph, Resource property) throws DatabaseException {\r
578         return getProperty(graph, name(graph, property));\r
579     }\r
580 \r
581     @Override\r
582     public Variable browse(ReadGraph graph, String suffix)\r
583             throws DatabaseException {\r
584         \r
585         if(suffix.isEmpty()) \r
586             return this;        \r
587         switch(suffix.charAt(0)) {\r
588         case '.': {\r
589             Variable parent = getParent(graph); \r
590             if(parent == null)\r
591                 throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").");\r
592             return parent.browse(graph, suffix.substring(1));\r
593         }\r
594         case '#': {\r
595             int segmentEnd = getSegmentEnd(suffix);\r
596             Variable property = getProperty(graph, \r
597                     decodeString(suffix.substring(1, segmentEnd)));\r
598             if(property == null) \r
599                 throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").");\r
600             return property.browse(graph, suffix.substring(segmentEnd));\r
601         }\r
602         case '/': {\r
603             int segmentEnd = getSegmentEnd(suffix);\r
604             Variable child = getChild(graph, \r
605                     decodeString(suffix.substring(1, segmentEnd)));\r
606             if(child == null) \r
607                 throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").");\r
608             return child.browse(graph, suffix.substring(segmentEnd));\r
609         }\r
610         default:\r
611             throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").");\r
612         }\r
613         \r
614     }\r
615 \r
616     private static int getSegmentEnd(String suffix) {\r
617         int pos;\r
618         for(pos=1;pos<suffix.length();++pos) {\r
619             char c = suffix.charAt(pos);\r
620             if(c == '/' || c == '#')\r
621                 break;\r
622         }\r
623         return pos;\r
624     }\r
625     \r
626     @Override\r
627     public Variable browsePossible(ReadGraph graph, String suffix)\r
628             throws DatabaseException {\r
629         if(suffix.isEmpty()) \r
630             return this;        \r
631         switch(suffix.charAt(0)) {\r
632         case '.': {\r
633             Variable parent = getParent(graph); \r
634             if(parent == null)\r
635                 return null;\r
636             return parent.browsePossible(graph, suffix.substring(1));\r
637         }\r
638         case '#': {\r
639             int segmentEnd = getSegmentEnd(suffix);\r
640             Variable property = getPossibleProperty(graph, \r
641                     decodeString(suffix.substring(1, segmentEnd)));\r
642             if(property == null) \r
643                 return null;\r
644             return property.browsePossible(graph, suffix.substring(segmentEnd));\r
645         }\r
646         case '/': {\r
647             int segmentEnd = getSegmentEnd(suffix);\r
648             Variable child = getPossibleChild(graph, \r
649                     decodeString(suffix.substring(1, segmentEnd)));\r
650             if(child == null) \r
651                 return null;\r
652             return child.browsePossible(graph, suffix.substring(segmentEnd));\r
653         }\r
654         default:\r
655             return null;\r
656         }\r
657     }\r
658 \r
659     @Override\r
660     public Variable browse(ReadGraph graph, Resource config)\r
661             throws DatabaseException {\r
662         Variable variable = browsePossible(graph, config);\r
663         if(variable == null)\r
664             throw new MissingVariableException("Didn't find a variable related to " + \r
665                     NameUtils.getSafeName(graph, config) + ".");\r
666         return variable;\r
667     }\r
668 \r
669     @Override\r
670     public Variable browsePossible(ReadGraph graph, Resource config)\r
671             throws DatabaseException {\r
672         Layer0 l0 = Layer0.getInstance(graph);\r
673         String name = (String)graph.getPossibleRelatedValue(config, l0.HasName, Bindings.STRING);\r
674         if (name == null)\r
675             return null;\r
676         return getPossibleChild(graph, name);\r
677     }\r
678 \r
679     @Override\r
680     public <T> T getInterface(ReadGraph graph, Class<T> clazz)\r
681             throws DatabaseException {\r
682         return null;\r
683     }\r
684 \r
685     @Override\r
686     public String getURI(ReadGraph graph) throws DatabaseException {\r
687         validate(graph);\r
688         Variable parent = getParent(graph);\r
689         if (parent == null)\r
690             throw new InvalidVariableException(this + " has no URI");\r
691         return parent.getURI(graph) + getRole(graph).getIdentifier() + encodeString(getName(graph));\r
692     }\r
693 \r
694     /**\r
695      * For debug messages.\r
696      * \r
697      * @param graph\r
698      * @return\r
699      * @throws DatabaseException\r
700      */\r
701     public String getPossibleURI(ReadGraph graph) throws DatabaseException {\r
702         Variable parent = getParent(graph);\r
703         if (parent == null)\r
704             return null;\r
705         if (parent instanceof AbstractVariable) {\r
706             String parentUri = ((AbstractVariable) parent).getPossibleURI(graph);\r
707             if (parentUri == null)\r
708                 return null;\r
709             return parentUri + getRole(graph).getIdentifier() + encodeString(getName(graph));\r
710         }\r
711         return null;\r
712     }\r
713 \r
714     public <T> T getPossibleValue(ReadGraph graph) throws DatabaseException {\r
715         try {\r
716             return getValue(graph);\r
717         } catch(DatabaseException e) {\r
718             return null;\r
719         }\r
720     }\r
721 \r
722     @Override\r
723     public Variant getVariantValue(ReadGraph graph) throws DatabaseException {\r
724         Binding binding = getPossibleDefaultBinding(graph);\r
725         if(binding != null) {\r
726                 Object value = getValue(graph, binding);\r
727                 return new Variant(binding, value);\r
728         } else {\r
729 //              System.err.println("no data type for " + getURI(graph));\r
730                 // TODO: hackish, consider doing something else here?\r
731                 Object value = getValue(graph);\r
732                 try {\r
733                                 binding = Bindings.OBJECT.getContentBinding(value);\r
734                         } catch (BindingException e) {\r
735                                 throw new DatabaseException(e);\r
736                         }\r
737                 return new Variant(binding, value);\r
738         }\r
739     }\r
740     \r
741     public Variant getPossibleVariantValue(ReadGraph graph) throws DatabaseException {\r
742         Binding binding = getPossibleDefaultBinding(graph);\r
743         if(binding != null) {\r
744                 Object value = getPossibleValue(graph, binding);\r
745                 if(value == null) return null;\r
746                 return new Variant(binding, value);\r
747         } else {\r
748                 Object value = getPossibleValue(graph);\r
749                 if(value == null) return null;\r
750                 try {\r
751                         // TODO: hackish, consider doing something else here?\r
752                         binding = value != null ? Bindings.getBinding(value.getClass()) : null;\r
753                         return new Variant(binding, value);\r
754                 } catch (BindingConstructionException e) {\r
755                         return null;\r
756                 }\r
757         }\r
758     }\r
759 \r
760     public <T> T getPossibleValue(ReadGraph graph, Binding binding) throws DatabaseException {\r
761         try {\r
762             return getValue(graph, binding);\r
763         } catch(MissingVariableValueException e) {\r
764             return null;\r
765         }\r
766     }\r
767 \r
768     public <T> T adapt(ReadGraph graph, Class<T> clazz) throws DatabaseException {\r
769         throw new AdaptionException(this + " does not support adaption to " + clazz);\r
770     }\r
771     \r
772     @Override\r
773     public <T> T adaptPossible(ReadGraph graph, Class<T> clazz) throws DatabaseException {\r
774         try {\r
775                 return adapt(graph, clazz);\r
776         } catch (AdaptionException e) {\r
777                 return null;\r
778         }\r
779     }\r
780     \r
781     \r
782     public static String encodeString(String string) throws DatabaseException {\r
783         if (string == null || "".equals(string)) return string;\r
784         return URIStringUtils.escape(string);\r
785     }\r
786     \r
787     public static String decodeString(String string) throws DatabaseException {\r
788         return URIStringUtils.unescape(string);\r
789     }\r
790     \r
791 \r
792         protected Variable getPossiblePropertyFromContext(ReadGraph graph, Resource context, String name) throws DatabaseException {\r
793 \r
794                 Map<String, Resource> predicates = graph.syncRequest(new PropertyMapOfResource(context));\r
795                 Resource property = predicates.get(name);\r
796                 if(property == null) return null;\r
797                 Resource object = graph.getSingleObject(context, property);\r
798                 Variable objectAdapter = graph.getPossibleContextualAdapter(object, new ModelledVariablePropertyDescriptorImpl(this, context, property), \r
799                                 ModelledVariablePropertyDescriptor.class, Variable.class);\r
800                 if(objectAdapter != null) return objectAdapter;\r
801                 return graph.getPossibleContextualAdapter(property, new ModelledVariablePropertyDescriptorImpl(this, context, property), \r
802                                 ModelledVariablePropertyDescriptor.class, Variable.class);\r
803                 \r
804         }\r
805         \r
806         protected Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Resource context, Map<String, Variable> properties) throws DatabaseException {\r
807 \r
808                 for(Map.Entry<String, Resource> entry : graph.syncRequest(new PropertyMapOfResource(context)).entrySet()) {\r
809                         String name = entry.getKey();\r
810                         Resource property = entry.getValue();\r
811                         Resource object = graph.getSingleObject(context, property);\r
812                         Variable objectAdapter = graph.getPossibleContextualAdapter(object, new ModelledVariablePropertyDescriptorImpl(this, context, property), \r
813                                         ModelledVariablePropertyDescriptor.class, Variable.class);\r
814                         if(objectAdapter != null) {\r
815                                 if(objectAdapter != null) {\r
816                                     if(properties == null) properties = new HashMap<String,Variable>();\r
817                                     properties.put(name, objectAdapter);\r
818                                 }\r
819                         } else {\r
820                                 Variable predicateAdapter = graph.getPossibleContextualAdapter(property, new ModelledVariablePropertyDescriptorImpl(this, context, property), \r
821                                                 ModelledVariablePropertyDescriptor.class, Variable.class);\r
822                                 if(predicateAdapter != null) {\r
823                     if(properties == null) properties = new HashMap<String,Variable>();\r
824                                     properties.put(name, predicateAdapter);\r
825                                 }\r
826                         }\r
827 \r
828                 }\r
829                 \r
830                 return properties;\r
831                 \r
832         }\r
833         \r
834         @Override\r
835         public Variable resolve(ReadGraph graph, RVIPart part) throws DatabaseException {\r
836                 if(part instanceof StringRVIPart) {\r
837                         StringRVIPart srp = (StringRVIPart)part;\r
838                         if(Role.CHILD.equals(srp.getRole())) return getChild(graph, srp.string);\r
839                         else if(Role.PROPERTY.equals(srp.getRole())) return getProperty(graph, srp.string);\r
840                 } else if(part instanceof ResourceRVIPart) {\r
841                         ResourceRVIPart rrp = (ResourceRVIPart)part;\r
842                         if(Role.CHILD.equals(rrp.getRole())) return resolveChild(graph, rrp.resource);\r
843                         else if(Role.PROPERTY.equals(rrp.getRole())) return resolveProperty(graph, rrp.resource);\r
844                 } else if(part instanceof GuidRVIPart) {\r
845                         GuidRVIPart grp = (GuidRVIPart)part;\r
846                         if(Role.CHILD.equals(grp.getRole())) return resolveChild(graph, grp);\r
847                         else if(Role.PROPERTY.equals(grp.getRole())) return resolveProperty(graph, grp);\r
848                 }\r
849                 throw new DatabaseException("Unrecognized RVIPart: " + part);\r
850         }\r
851 \r
852         @Override\r
853         public Variable resolvePossible(ReadGraph graph, RVIPart part) throws DatabaseException {\r
854                 if(part instanceof StringRVIPart) {\r
855                         StringRVIPart srp = (StringRVIPart)part;\r
856                         if(Role.CHILD.equals(srp.getRole())) return getPossibleChild(graph, srp.string);\r
857                         else if(Role.PROPERTY.equals(srp.getRole())) return getPossibleProperty(graph, srp.string);\r
858                 } else if(part instanceof ResourceRVIPart) {\r
859                         ResourceRVIPart rrp = (ResourceRVIPart)part;\r
860                         if(Role.CHILD.equals(rrp.getRole())) return resolvePossibleChild(graph, rrp.resource);\r
861                         else if(Role.PROPERTY.equals(rrp.getRole())) return resolvePossibleProperty(graph, rrp.resource);\r
862                 } else if(part instanceof GuidRVIPart) {\r
863                         GuidRVIPart grp = (GuidRVIPart)part;\r
864                         if(Role.CHILD.equals(grp.getRole())) return resolvePossibleChild(graph, grp);\r
865                         else if(Role.PROPERTY.equals(grp.getRole())) return resolvePossibleProperty(graph, grp);\r
866                 }\r
867                 throw new DatabaseException("Unrecognized RVIPart: " + part);\r
868         }\r
869 \r
870         @Override\r
871         public Datatype getDatatype(ReadGraph graph) throws DatabaseException {\r
872                 throw new DatabaseException("No data type.");\r
873         }\r
874 \r
875         public Binding getDefaultBinding(ReadGraph graph) throws DatabaseException {\r
876                 Datatype type = getDatatype(graph);\r
877                 return Bindings.getBinding(type);\r
878         }\r
879         \r
880         public Binding getPossibleDefaultBinding(ReadGraph graph) throws DatabaseException {\r
881         try {\r
882             return getDefaultBinding(graph);\r
883         } catch(DatabaseException e) {\r
884             return null;\r
885         }\r
886         }\r
887 \r
888         @Override\r
889         public Datatype getPossibleDatatype(ReadGraph graph) throws DatabaseException {\r
890         try {\r
891             return getDatatype(graph);\r
892         } catch(DatabaseException e) {\r
893             return null;\r
894         }\r
895         }\r
896         \r
897 //      public Binding getPossibleDefaultBinding(ReadGraph graph) throws DatabaseException {\r
898 //              \r
899 //              Datatype type = getPossibleDatatype(graph);\r
900 //              if(type == null) return null;\r
901 //              return Bindings.getBinding(type);\r
902 //\r
903 //      }\r
904 //\r
905 //      @Override\r
906 //      public Datatype getPossibleDatatype(ReadGraph graph) throws DatabaseException {\r
907 //              \r
908 //              Variant vt = getVariantValue(graph);\r
909 //              if(vt == null) return null;\r
910 //              Binding binding = vt.getBinding();\r
911 //              if(binding == null) return null;\r
912 //              return binding.type();\r
913 //\r
914 //      }\r
915 \r
916         @Override\r
917         public Variable getPredicate(ReadGraph graph) throws DatabaseException {\r
918                 throw new DatabaseException(getClass().getSimpleName() + ": No predicate property for " + getPossibleURI(graph));\r
919         }\r
920 \r
921         @Override\r
922         public Variable getPossiblePredicate(ReadGraph graph) throws DatabaseException {\r
923                 try {\r
924             return getPredicate(graph);\r
925         } catch(DatabaseException e) {\r
926             return null;\r
927         }\r
928         }\r
929         \r
930         @Override\r
931         public Resource getPredicateResource(ReadGraph graph) throws DatabaseException {\r
932                 Variable predicate = getPredicate(graph);\r
933                 if(predicate == null) throw new DatabaseException(getClass().getSimpleName() + ": No predicate property for " + getPossibleURI(graph));\r
934                 return predicate.getRepresents(graph);\r
935         }\r
936         \r
937         @Override\r
938         public Resource getPossiblePredicateResource(ReadGraph graph) throws DatabaseException {\r
939                 Variable predicate = getPossiblePredicate(graph);\r
940                 if(predicate == null) return null;\r
941                 else return predicate.getPossibleRepresents(graph);\r
942         }\r
943 \r
944         @Override\r
945         public Resource getPossibleRepresents(ReadGraph graph) throws DatabaseException {\r
946         try {\r
947             return getRepresents(graph);\r
948         } catch(DatabaseException e) {\r
949             return null;\r
950         }\r
951         }\r
952 \r
953         @Override\r
954         public Resource getPossibleType(ReadGraph graph) throws DatabaseException {\r
955         Resource resource = getPossibleRepresents(graph);\r
956         if(resource == null) {\r
957                 String uri = getPossiblePropertyValue(graph, "typeURI");\r
958                 if(uri != null) return graph.syncRequest(new PossibleResource(uri), TransientCacheAsyncListener.<Resource>instance());\r
959             return null;\r
960         }\r
961         return graph.getPossibleObject(resource, Layer0.getInstance(graph).InstanceOf);\r
962         }\r
963 \r
964     public Resource getType(ReadGraph graph, Resource baseType) throws DatabaseException {\r
965         Resource resource = getPossibleRepresents(graph);\r
966         if(resource == null) {\r
967                 String uri = getPossiblePropertyValue(graph, "typeURI");\r
968                 if(uri != null) return graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri), TransientCacheAsyncListener.<Resource>instance());\r
969             throw new DatabaseException("No type for " + getURI(graph));\r
970         }\r
971         return graph.getSingleType(resource, baseType);\r
972     }\r
973 \r
974         @Override\r
975         public Resource getPossibleType(ReadGraph graph, Resource baseType) throws DatabaseException {\r
976         Resource resource = getPossibleRepresents(graph);\r
977         if(resource == null) {\r
978                 String uri = getPossiblePropertyValue(graph, "typeURI");\r
979                 if(uri != null) {\r
980                         Resource type = graph.syncRequest(new PossibleResource(uri), TransientCacheAsyncListener.<Resource>instance());\r
981                         if(type == null) return null;\r
982                         if(graph.isInheritedFrom(type, baseType)) return type;\r
983                         else return null;\r
984                 }\r
985             return null;\r
986         }\r
987         return graph.getPossibleType(resource, baseType);\r
988         }\r
989 \r
990     public Map<String, Variable> collectDomainProperties(ReadGraph graph, String classification, Map<String, Variable> map) throws DatabaseException {\r
991         Map<String,Variable> all = collectDomainProperties(graph, null);\r
992         for(Map.Entry<String, Variable> entry : all.entrySet()) {\r
993                 Set<String> classifications = entry.getValue().getClassifications(graph);\r
994                 if(classifications.contains(classification)) {\r
995                         if(map == null) map = new HashMap<String,Variable>();\r
996                         map.put(entry.getKey(), entry.getValue());\r
997                 }\r
998         }\r
999         return map;\r
1000     }\r
1001     \r
1002     @Override\r
1003     public RVI getPossibleRVI(ReadGraph graph) throws DatabaseException {\r
1004         try {\r
1005             return getRVI(graph);\r
1006         } catch(DatabaseException e) {\r
1007             return null;\r
1008         }\r
1009     }\r
1010 \r
1011 }\r