1 package org.simantics.db.layer0.variable;
3 import gnu.trove.map.hash.THashMap;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.HashMap;
11 import org.simantics.databoard.Bindings;
12 import org.simantics.databoard.Databoard;
13 import org.simantics.databoard.binding.Binding;
14 import org.simantics.databoard.binding.StringBinding;
15 import org.simantics.databoard.binding.error.BindingConstructionException;
16 import org.simantics.databoard.binding.error.BindingException;
17 import org.simantics.databoard.binding.mutable.Variant;
18 import org.simantics.databoard.type.Datatype;
19 import org.simantics.databoard.util.URIStringUtils;
20 import org.simantics.datatypes.literal.GUID;
21 import org.simantics.db.ReadGraph;
22 import org.simantics.db.Resource;
23 import org.simantics.db.WriteGraph;
24 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
25 import org.simantics.db.common.request.PossibleIndexRoot;
26 import org.simantics.db.common.request.PropertyMapOfResource;
27 import org.simantics.db.common.utils.NameUtils;
28 import org.simantics.db.exception.AdaptionException;
29 import org.simantics.db.exception.DatabaseException;
30 import org.simantics.db.layer0.exception.InvalidVariableException;
31 import org.simantics.db.layer0.exception.MissingVariableException;
32 import org.simantics.db.layer0.exception.MissingVariableValueException;
33 import org.simantics.db.layer0.request.PossibleResource;
34 import org.simantics.db.layer0.request.PropertyInfo;
35 import org.simantics.db.layer0.request.VariableRVIRequest;
36 import org.simantics.db.layer0.variable.RVI.GuidRVIPart;
37 import org.simantics.db.layer0.variable.RVI.RVIPart;
38 import org.simantics.db.layer0.variable.RVI.ResourceRVIPart;
39 import org.simantics.db.layer0.variable.RVI.StringRVIPart;
40 import org.simantics.db.layer0.variable.Variables.Role;
41 import org.simantics.layer0.Layer0;
42 import org.simantics.scl.runtime.SCLContext;
43 import org.simantics.scl.runtime.function.Function2;
46 * Abstract implementation of Variable -interface.
48 * @author Hannu Niemistö
50 public abstract class AbstractVariable implements Variable {
52 @SuppressWarnings("rawtypes")
53 final public VariableNode node;
55 public AbstractVariable(@SuppressWarnings("rawtypes") VariableNode node) {
60 * Returns a variable that is not one of the standard properties listed
61 * in <a href="https://www.simantics.org/wiki/index.php/Org.simantics.db.layer0.variable.Variable#Standard_required_properties">specification</a>.
63 protected abstract Variable getPossibleDomainProperty(ReadGraph graph, String name) throws DatabaseException;
64 public abstract Variable getPossibleExtraProperty(ReadGraph graph, String name) throws DatabaseException;
65 public abstract Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException;
67 public abstract void collectExtraProperties(ReadGraph graph, Map<String, Variable> properties) throws DatabaseException;
68 public abstract Map<String, Variable> collectDomainProperties(ReadGraph graph, Map<String, Variable> map) throws DatabaseException;
69 public abstract Collection<Variable> getChildren(ReadGraph graph) throws DatabaseException;
71 public abstract <T> T getValue(ReadGraph graph) throws DatabaseException;
72 public abstract <T> T getValue(ReadGraph graph, Binding binding) throws DatabaseException;
74 public abstract void setValue(WriteGraph graph, Object value, Binding binding) throws DatabaseException;
75 public abstract String getName(ReadGraph graph) throws DatabaseException;
76 //public abstract Object getSerialized(ReadGraph graph) throws DatabaseException;
77 public abstract Variable getParent(ReadGraph graph) throws DatabaseException;
78 public abstract Role getRole(ReadGraph graph) throws DatabaseException;
79 public abstract Resource getRepresents(ReadGraph graph) throws DatabaseException;
81 public abstract Set<String> getClassifications(ReadGraph graph) throws DatabaseException;
84 public PropertyInfo getPropertyInfo(ReadGraph graph) throws DatabaseException {
85 throw new InvalidVariableException("PropertyInfo is not available");
89 public Resource getIndexRoot(ReadGraph graph) throws DatabaseException {
90 Resource represents = getPossibleRepresents(graph);
91 if(represents != null) return graph.syncRequest(new PossibleIndexRoot(represents));
92 Variable parent = getParent(graph);
93 if(parent == null) return null;
94 return parent.getIndexRoot(graph);
97 public void validate(ReadGraph graph) throws DatabaseException {
100 public String getIdentifier() {
101 return getClass().getSimpleName();
106 public Role getPossibleRole(ReadGraph graph) throws DatabaseException {
108 return getRole(graph);
109 } catch (DatabaseException e) {
114 protected Variable resolveChild(ReadGraph graph, Resource resource) throws DatabaseException {
115 String rName = graph.getRelatedValue(resource, Layer0.getInstance(graph).HasName, Bindings.STRING);
116 for(Variable child : browseChildren(graph)) {
117 String name = child.getPossiblePropertyValue(graph, Variables.NAME, Bindings.STRING);
118 if(rName.equals(name)) return child;
120 throw new MissingVariableException("Could not resolve child " + rName, resource);
123 protected Variable resolveChild(ReadGraph graph, GuidRVIPart part) throws DatabaseException {
124 return StandardRVIResolver.resolveChildDefault(graph, this, part);
127 protected Variable resolveProperty(ReadGraph graph, Resource resource) throws DatabaseException {
128 String rName = graph.getRelatedValue(resource, Layer0.getInstance(graph).HasName, Bindings.STRING);
129 for(Variable child : browseProperties(graph)) {
130 String name = child.getPossiblePropertyValue(graph, Variables.NAME, Bindings.STRING);
131 if(rName.equals(name)) return child;
133 throw new MissingVariableException("Could not resolve child " + rName, resource);
136 protected Variable resolveProperty(ReadGraph graph, GuidRVIPart part) throws DatabaseException {
137 return StandardRVIResolver.resolvePropertyDefault(graph, this, part);
140 protected Variable resolvePossibleChild(ReadGraph graph, Resource resource) throws DatabaseException {
141 String rName = graph.getRelatedValue(resource, Layer0.getInstance(graph).HasName, Bindings.STRING);
142 for(Variable child : browseChildren(graph)) {
143 String name = child.getPossiblePropertyValue(graph, Variables.NAME, Bindings.STRING);
144 if(rName.equals(name)) return child;
149 protected Variable resolvePossibleChild(ReadGraph graph, GuidRVIPart part) throws DatabaseException {
150 Layer0 L0 = Layer0.getInstance(graph);
151 for(Variable child : browseChildren(graph)) {
152 GUID id = child.getPossiblePropertyValue(graph, L0.identifier, GUID.BINDING);
154 if(id.mostSignificant == part.mostSignificant && id.leastSignificant == part.leastSignificant)
161 protected Variable resolvePossibleProperty(ReadGraph graph, Resource resource) throws DatabaseException {
162 String rName = graph.getRelatedValue(resource, Layer0.getInstance(graph).HasName, Bindings.STRING);
163 for(Variable child : browseProperties(graph)) {
164 String name = child.getPossiblePropertyValue(graph, Variables.NAME, Bindings.STRING);
165 if(rName.equals(name)) return child;
170 protected Variable resolvePossibleProperty(ReadGraph graph, GuidRVIPart part) throws DatabaseException {
171 Layer0 L0 = Layer0.getInstance(graph);
172 for(Variable child : browseProperties(graph)) {
173 GUID id = child.getPossiblePropertyValue(graph, L0.identifier, GUID.BINDING);
175 if(id.mostSignificant == part.mostSignificant && id.leastSignificant == part.leastSignificant)
182 public String getLabel(ReadGraph graph) throws DatabaseException {
183 return getName(graph);
186 public String getPossibleLabel(ReadGraph graph) throws DatabaseException {
187 Resource represents = getPossibleRepresents(graph);
188 if(represents == null) return null;
189 return graph.getPossibleRelatedValue2(represents, graph.getService(Layer0.class).HasLabel, getParent(graph), Bindings.STRING);
192 public RVIPart getRVIPart(ReadGraph graph) throws DatabaseException {
193 throw new UnsupportedOperationException();
197 public RVI getRVI(ReadGraph graph) throws DatabaseException {
198 Databoard databoard = graph.getService( Databoard.class );
199 Binding rviBinding = databoard.getBindingUnchecked( RVI.class );
200 if(Variables.isContext(graph, this)) {
201 return RVI.empty( rviBinding );
203 Variable parent = getParent(graph);
205 // TODO: consider using a more suitable exception here to better convey the situation.
206 throw new MissingVariableException("no parent for variable " + this + " (URI=" + getPossibleURI(graph) + ")", getPossibleRepresents(graph));
207 RVI base = graph.syncRequest(new VariableRVIRequest(parent));
208 RVIPart part = getRVIPart(graph);
209 return new RVIBuilder(base).append(part).toRVI();
213 protected Variable getDomainProperty(ReadGraph graph, String name) throws DatabaseException {
214 Variable property = getPossibleDomainProperty(graph, name);
216 throw new MissingVariableException(getIdentifier() + ": Didn't find property " + name + ".", getPossibleRepresents(graph));
220 protected void addProperty(Map<String, Variable> properties, String name, Object value, Binding binding) {
222 properties.put(name, new ConstantPropertyVariable(this, name, value, binding));
226 protected Variable getNameVariable(ReadGraph graph) throws DatabaseException {
227 return new ConstantPropertyVariable(this, Variables.NAME, getName(graph), Bindings.STRING);
230 protected Variable getLabelVariable(ReadGraph graph) throws DatabaseException {
231 return new ConstantPropertyVariable(this, Variables.LABEL, getPossibleLabel(graph), Bindings.STRING);
234 final public Collection<Variable> browseProperties(ReadGraph graph) throws DatabaseException {
235 return getProperties(graph);
238 private Map<String, Variable> getPropertyMap(ReadGraph graph, String classification) throws DatabaseException {
239 return collectDomainProperties(graph, classification, null);
242 final static class PropertyMap extends THashMap<String,Variable> {
244 final private Variable variable;
246 PropertyMap(Variable variable) {
247 this.variable = variable;
250 private Variable getTypeVariable() {
252 return new AbstractConstantPropertyVariable(variable, Variables.TYPE, null) {
254 @SuppressWarnings("unchecked")
256 public <T> T getValue(ReadGraph graph) throws DatabaseException {
257 Resource represents = parent.getRepresents(graph);
258 if(represents == null) return null;
259 return (T)graph.getPossibleType(represents, Layer0.getInstance(graph).Entity);
263 public <T> T getValue(ReadGraph graph, Binding binding) throws DatabaseException {
264 return getValue(graph);
270 private Variable getURIVariable() {
272 return new AbstractConstantPropertyVariable(variable, Variables.URI, null) {
274 @SuppressWarnings("unchecked")
276 public <T> T getValue(ReadGraph graph) throws DatabaseException {
277 return (T)variable.getURI(graph);
281 public <T> T getValue(ReadGraph graph, Binding binding) throws DatabaseException {
282 return getValue(graph);
288 public Variable get(Object key) {
289 Variable result = super.get(key);
290 if(result != null) return result;
292 if(Variables.TYPE.equals(key)) return getTypeVariable();
293 else if(Variables.URI.equals(key)) return getURIVariable();
300 private Map<String, Variable> getPropertyMap(ReadGraph graph) throws DatabaseException {
301 PropertyMap properties = new PropertyMap(this);
302 // Map<String, Variable> properties = new HashMap<String, Variable>();
304 // properties.put(Variables.NAME, getNameVariable(graph));
305 // } catch (DatabaseException e) {
306 // // A variable that has no name doesn't exist by definition.
307 // // Therefore it can't have any properties.
308 // return Collections.emptyMap();
311 // Variable labelVariable = getLabelVariable(graph);
312 // if(labelVariable != null) properties.put(Variables.LABEL, getLabelVariable(graph));
313 // } catch (DatabaseException e) {
314 // // Label not absolutely mandatory.
316 // addProperty(properties, Variables.TYPE, getPossibleType(graph), null);
317 // addProperty(properties, Variables.URI, getPossibleURI(graph), Bindings.STRING);
318 //addProperty(properties, Variables.SERIALISED, getSerialized(graph), Bindings.STRING);
319 //addProperty(properties, Variables.PARENT, getParent(graph), null);
320 // addProperty(properties, Variables.ROLE, getRole(graph), Bindings.STRING);
321 // addProperty(properties, Variables.REPRESENTS, getPossibleRepresents(graph), null);
322 collectExtraProperties(graph, properties);
323 collectDomainProperties(graph, properties);
328 public Collection<Variable> getProperties(ReadGraph graph) throws DatabaseException {
329 return getPropertyMap(graph).values();
332 public Collection<Variable> getProperties(ReadGraph graph, String classification) throws DatabaseException {
333 Map<String,Variable> propertyMap = getPropertyMap(graph, classification);
334 if(propertyMap == null) return Collections.emptyList();
335 else return propertyMap.values();
339 public Collection<Variable> getProperties(ReadGraph graph, Resource property) throws DatabaseException {
340 return getProperties(graph, uri(graph, property));
343 final public Collection<Variable> browseChildren(ReadGraph graph) throws DatabaseException {
344 return getChildren(graph);
348 public Variable getPossibleProperty(ReadGraph graph, String name)
349 throws DatabaseException {
350 if(Variables.NAME.equals(name)) {
351 return getNameVariable(graph);
353 if(Variables.LABEL.equals(name)) {
354 return getLabelVariable(graph);
356 if(Variables.TYPE.equals(name)) {
357 Object value = getPossibleType(graph);
359 return new ConstantPropertyVariable(this, name, value, null);
361 if(Variables.URI.equals(name)) {
362 // TODO: getPossibleURI or getURI?
363 Object value = getURI(graph);
365 return new ConstantPropertyVariable(this, name, value, Bindings.STRING);
367 // if(Variables.SERIALISED.equals(name)) {
368 // Object value = getSerialized(graph);
370 // return new ConstantPropertyVariable(this, name, value, Bindings.STRING);
372 /*if(Variables.PARENT.equals(name)) {
373 Object value = getParent(graph);
375 return new ConstantPropertyVariable(this, name, value, null);
377 // if(Variables.ROLE.equals(name)) {
378 // Object value = getRole(graph);
380 // return new ConstantPropertyVariable(this, name, value, null);
382 // if(Variables.REPRESENTS.equals(name)) {
383 // Object value = getRepresents(graph);
385 // return new ConstantPropertyVariable(this, name, value, null);
387 Variable extra = getPossibleExtraProperty(graph, name);
388 if(extra != null) return extra;
389 return getPossibleDomainProperty(graph, name);
393 public Variable getPossibleProperty(ReadGraph graph, Resource property) throws DatabaseException {
394 return getPossibleProperty(graph, name(graph, property));
397 @SuppressWarnings("unchecked")
398 protected <T> T checkNull(ReadGraph graph, Object value) throws DatabaseException {
400 throw new MissingVariableValueException(getClass().getSimpleName() + ": Didn't find value for " + getPossibleURI(graph));
404 private String name(ReadGraph graph, Resource property) throws DatabaseException {
405 return graph.getRelatedValue(property, Layer0.getInstance(graph).HasName, Bindings.STRING);
408 private String uri(ReadGraph graph, Resource property) throws DatabaseException {
409 return graph.getURI(property);
413 public <T> T getPropertyValue(ReadGraph graph, String name) throws DatabaseException {
414 if(Variables.LABEL.equals(name)) return checkNull(graph, getLabel(graph));
415 Variable result = getDomainProperty(graph, name);
416 if(result != null) return result.getValue(graph);
417 if(Variables.NAME.equals(name)) return checkNull(graph, getName(graph));
418 if(Variables.TYPE.equals(name)) return checkNull(graph, getPossibleType(graph));
419 if(Variables.URI.equals(name)) return checkNull(graph, getURI(graph));
420 // if(Variables.SERIALISED.equals(name)) return checkNull(graph, getSerialized(graph));
421 // if(Variables.ROLE.equals(name)) return checkNull(graph, getRole(graph));
422 // if(Variables.REPRESENTS.equals(name)) return checkNull(graph, getRepresents(graph));
423 Variable extra = getPossibleExtraProperty(graph, name);
424 if(extra != null) return extra.getValue(graph);
429 public <T> T getPropertyValue(ReadGraph graph, Resource property) throws DatabaseException {
430 return getPropertyValue(graph, name(graph, property));
433 @SuppressWarnings("unchecked")
435 public <T> T getPossiblePropertyValue(ReadGraph graph, String name)
436 throws DatabaseException {
438 Variable property = getPossibleDomainProperty(graph, name);
439 if(property != null) return property.getPossibleValue(graph);
441 if(Variables.NAME.equals(name)) return (T)getName(graph);
442 if(Variables.LABEL.equals(name)) return (T)getLabel(graph);
443 if(Variables.TYPE.equals(name)) return (T)getPossibleType(graph);
444 if(Variables.URI.equals(name)) return (T)getURI(graph);
445 // if(Variables.SERIALISED.equals(name)) return (T)getSerialized(graph);
446 // if(Variables.ROLE.equals(name)) return (T)getRole(graph);
447 // if(Variables.REPRESENTS.equals(name)) return (T)getRepresents(graph);
449 Variable extra = getPossibleExtraProperty(graph, name);
450 if(extra != null) return extra.getPossibleValue(graph);
457 public <T> T getPossiblePropertyValue(ReadGraph graph, Resource property) throws DatabaseException {
458 return getPossiblePropertyValue(graph, name(graph, property));
461 @SuppressWarnings("unchecked")
463 public <T> T getPropertyValue(ReadGraph graph, String name, Binding binding) throws DatabaseException {
464 if (binding instanceof StringBinding) {
465 StringBinding sb = (StringBinding) binding;
467 if (Variables.NAME.equals(name))
468 return (T) sb.create((String) checkNull(graph, getName(graph)));
469 if (Variables.LABEL.equals(name))
470 return (T) sb.create((String) checkNull(graph, getLabel(graph)));
471 if (Variables.URI.equals(name))
472 return (T) sb.create((String) checkNull(graph, getURI(graph)));
473 // if(Variables.SERIALISED.equals(name)) return
474 // (T)sb.create((String)checkNull(graph, getSerialized(graph)));
475 } catch (BindingException e) {
476 throw new org.simantics.db.exception.BindingException("Could not get value for property " + name + " with binding " + binding, e);
479 Variable property = getPossibleExtraProperty(graph, name);
481 return property.getValue(graph, binding);
482 property = getPossibleDomainProperty(graph, name);
484 throw new MissingVariableException("Didn't find property " + name + " for " + this + ".", getPossibleRepresents(graph));
485 return property.getValue(graph, binding);
489 public <T> T getPropertyValue(ReadGraph graph, Resource property, Binding binding) throws DatabaseException {
490 return getPropertyValue(graph, name(graph, property), binding);
493 @SuppressWarnings("unchecked")
495 public <T> T getPossiblePropertyValue(ReadGraph graph, String name,
496 Binding binding) throws DatabaseException {
497 if(binding instanceof StringBinding) {
498 StringBinding sb = (StringBinding)binding;
500 if(Variables.NAME.equals(name)) return (T)sb.create((String)getName(graph));
501 if(Variables.LABEL.equals(name)) return (T)sb.create((String)getLabel(graph));
502 if(Variables.URI.equals(name)) return (T)sb.create((String)getURI(graph));
503 // if(Variables.SERIALISED.equals(name)) return (T)sb.create((String)getSerialized(graph));
504 } catch(BindingException e) {
505 throw new org.simantics.db.exception.BindingException("Could not get property value for " + name + " with binding " + binding, e);
508 Variable property = getPossibleExtraProperty(graph, name);
510 return property.getPossibleValue(graph, binding);
511 property = getPossibleDomainProperty(graph, name);
514 return property.getPossibleValue(graph, binding);
518 public <T> T getPossiblePropertyValue(ReadGraph graph, Resource property, Binding binding) throws DatabaseException {
519 return getPossiblePropertyValue(graph, name(graph, property), binding);
523 public void setValue(WriteGraph graph, Object value) throws DatabaseException {
525 setValue(graph, value, Bindings.getBinding(value.getClass()));
526 } catch (BindingConstructionException e) {
527 throw new org.simantics.db.exception.BindingException("Could not set " + String.valueOf(value) + " value for " + getRepresents(graph), e);
532 public void setPropertyValue(WriteGraph graph, String name, Object value) throws DatabaseException {
533 getProperty(graph, name).setValue(graph, value);
537 public void setPropertyValue(WriteGraph graph, Resource property, Object value) throws DatabaseException {
538 setPropertyValue(graph, name(graph, property), value);
542 public void setPropertyValue(WriteGraph graph, String name, Object value,
543 Binding binding) throws DatabaseException {
544 getProperty(graph, name).setValue(graph, value, binding);
548 public void setPropertyValue(WriteGraph graph, Resource property, Object value, Binding binding) throws DatabaseException {
549 setPropertyValue(graph, name(graph, property), value, binding);
553 public Variable getChild(ReadGraph graph, String name)
554 throws DatabaseException {
555 Variable child = getPossibleChild(graph, name);
557 throw new MissingVariableException(getURI(graph) + ": didn't find child " + name + " for " + getIdentifier() + ".", getPossibleRepresents(graph));
562 public Variable getProperty(ReadGraph graph, String name) throws DatabaseException {
563 Variable result = getPossibleProperty(graph, name);
565 throw new MissingVariableException(getClass().getSimpleName() + ": Didn't find property " + name + " for " + getPossibleURI(graph) + ".", getPossibleRepresents(graph));
570 public Variable getProperty(ReadGraph graph, Resource property) throws DatabaseException {
571 return getProperty(graph, name(graph, property));
575 public Variable browse(ReadGraph graph, String suffix)
576 throws DatabaseException {
580 switch(suffix.charAt(0)) {
582 Variable parent = getParent(graph);
584 throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").", getPossibleRepresents(graph));
585 return parent.browse(graph, suffix.substring(1));
588 int segmentEnd = getSegmentEnd(suffix);
589 Variable property = getProperty(graph,
590 decodeString(suffix.substring(1, segmentEnd)));
592 throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").", getPossibleRepresents(graph));
593 return property.browse(graph, suffix.substring(segmentEnd));
596 int segmentEnd = getSegmentEnd(suffix);
597 Variable child = getChild(graph,
598 decodeString(suffix.substring(1, segmentEnd)));
600 throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").", getPossibleRepresents(graph));
601 return child.browse(graph, suffix.substring(segmentEnd));
604 throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").", getPossibleRepresents(graph));
609 private static int getSegmentEnd(String suffix) {
611 for(pos=1;pos<suffix.length();++pos) {
612 char c = suffix.charAt(pos);
613 if(c == '/' || c == '#')
620 public Variable browsePossible(ReadGraph graph, String suffix)
621 throws DatabaseException {
624 switch(suffix.charAt(0)) {
626 Variable parent = getParent(graph);
629 return parent.browsePossible(graph, suffix.substring(1));
632 int segmentEnd = getSegmentEnd(suffix);
633 Variable property = getPossibleProperty(graph,
634 decodeString(suffix.substring(1, segmentEnd)));
637 return property.browsePossible(graph, suffix.substring(segmentEnd));
640 int segmentEnd = getSegmentEnd(suffix);
641 Variable child = getPossibleChild(graph,
642 decodeString(suffix.substring(1, segmentEnd)));
645 return child.browsePossible(graph, suffix.substring(segmentEnd));
653 public Variable browse(ReadGraph graph, Resource config)
654 throws DatabaseException {
655 Variable variable = browsePossible(graph, config);
657 throw new MissingVariableException("Didn't find a variable related to " +
658 NameUtils.getSafeName(graph, config) + ".", config);
663 public Variable browsePossible(ReadGraph graph, Resource config)
664 throws DatabaseException {
665 Layer0 l0 = Layer0.getInstance(graph);
666 String name = (String)graph.getPossibleRelatedValue(config, l0.HasName, Bindings.STRING);
669 return getPossibleChild(graph, name);
673 public <T> T getInterface(ReadGraph graph, Class<T> clazz)
674 throws DatabaseException {
679 public String getURI(ReadGraph graph) throws DatabaseException {
681 Variable parent = getParent(graph);
683 throw new InvalidVariableException(this + " has no URI");
684 return parent.getURI(graph) + getRole(graph).getIdentifier() + encodeString(getName(graph));
688 * For debug messages.
692 * @throws DatabaseException
694 public String getPossibleURI(ReadGraph graph) throws DatabaseException {
695 Variable parent = getParent(graph);
698 if (parent instanceof AbstractVariable) {
699 String parentUri = ((AbstractVariable) parent).getPossibleURI(graph);
700 if (parentUri == null)
702 return parentUri + getRole(graph).getIdentifier() + encodeString(getName(graph));
707 public <T> T getPossibleValue(ReadGraph graph) throws DatabaseException {
709 return getValue(graph);
710 } catch(DatabaseException e) {
716 public Variant getVariantValue(ReadGraph graph) throws DatabaseException {
717 Binding binding = getPossibleDefaultBinding(graph);
718 if(binding != null) {
719 Object value = getValue(graph, binding);
720 return new Variant(binding, value);
722 // System.err.println("no data type for " + getURI(graph));
723 // TODO: hackish, consider doing something else here?
724 Object value = getValue(graph);
726 binding = Bindings.OBJECT.getContentBinding(value);
727 } catch (BindingException e) {
728 throw new org.simantics.db.exception.BindingException("Could not bind variant value " + String.valueOf(value) + " for " + getRepresents(graph), e);
730 return new Variant(binding, value);
734 public Variant getPossibleVariantValue(ReadGraph graph) throws DatabaseException {
735 Binding binding = getPossibleDefaultBinding(graph);
736 if(binding != null) {
737 Object value = getPossibleValue(graph, binding);
738 if(value == null) return null;
739 return new Variant(binding, value);
741 Object value = getPossibleValue(graph);
742 if(value == null) return null;
744 // TODO: hackish, consider doing something else here?
745 binding = value != null ? Bindings.getBinding(value.getClass()) : null;
746 return new Variant(binding, value);
747 } catch (BindingConstructionException e) {
753 public <T> T getPossibleValue(ReadGraph graph, Binding binding) throws DatabaseException {
755 return getValue(graph, binding);
756 } catch(MissingVariableValueException e) {
761 public <T> T adapt(ReadGraph graph, Class<T> clazz) throws DatabaseException {
762 throw new AdaptionException(this + " does not support adaption to " + clazz);
766 public <T> T adaptPossible(ReadGraph graph, Class<T> clazz) throws DatabaseException {
768 return adapt(graph, clazz);
769 } catch (AdaptionException e) {
775 public static String encodeString(String string) throws DatabaseException {
776 if (string == null || "".equals(string)) return string;
777 return URIStringUtils.escape(string);
780 public static String decodeString(String string) throws DatabaseException {
781 return URIStringUtils.unescape(string);
785 protected Variable getPossiblePropertyFromContext(ReadGraph graph, Resource context, String name) throws DatabaseException {
787 Map<String, Resource> predicates = graph.syncRequest(new PropertyMapOfResource(context));
788 Resource property = predicates.get(name);
789 if(property == null) return null;
790 Resource object = graph.getSingleObject(context, property);
791 Variable objectAdapter = graph.getPossibleContextualAdapter(object, new ModelledVariablePropertyDescriptorImpl(this, context, property),
792 ModelledVariablePropertyDescriptor.class, Variable.class);
793 if(objectAdapter != null) return objectAdapter;
794 return graph.getPossibleContextualAdapter(property, new ModelledVariablePropertyDescriptorImpl(this, context, property),
795 ModelledVariablePropertyDescriptor.class, Variable.class);
799 protected Map<String, Variable> collectPropertiesFromContext(ReadGraph graph, Resource context, Map<String, Variable> properties) throws DatabaseException {
801 for(Map.Entry<String, Resource> entry : graph.syncRequest(new PropertyMapOfResource(context)).entrySet()) {
802 String name = entry.getKey();
803 Resource property = entry.getValue();
804 Resource object = graph.getSingleObject(context, property);
805 Variable objectAdapter = graph.getPossibleContextualAdapter(object, new ModelledVariablePropertyDescriptorImpl(this, context, property),
806 ModelledVariablePropertyDescriptor.class, Variable.class);
807 if(objectAdapter != null) {
808 if(objectAdapter != null) {
809 if(properties == null) properties = new HashMap<String,Variable>();
810 properties.put(name, objectAdapter);
813 Variable predicateAdapter = graph.getPossibleContextualAdapter(property, new ModelledVariablePropertyDescriptorImpl(this, context, property),
814 ModelledVariablePropertyDescriptor.class, Variable.class);
815 if(predicateAdapter != null) {
816 if(properties == null) properties = new HashMap<String,Variable>();
817 properties.put(name, predicateAdapter);
828 public Variable resolve(ReadGraph graph, RVIPart part) throws DatabaseException {
829 if(part instanceof StringRVIPart) {
830 StringRVIPart srp = (StringRVIPart)part;
831 if(Role.CHILD.equals(srp.getRole())) return getChild(graph, srp.string);
832 else if(Role.PROPERTY.equals(srp.getRole())) return getProperty(graph, srp.string);
833 } else if(part instanceof ResourceRVIPart) {
834 ResourceRVIPart rrp = (ResourceRVIPart)part;
835 if(Role.CHILD.equals(rrp.getRole())) return resolveChild(graph, rrp.resource);
836 else if(Role.PROPERTY.equals(rrp.getRole())) return resolveProperty(graph, rrp.resource);
837 } else if(part instanceof GuidRVIPart) {
838 GuidRVIPart grp = (GuidRVIPart)part;
839 if(Role.CHILD.equals(grp.getRole())) return resolveChild(graph, grp);
840 else if(Role.PROPERTY.equals(grp.getRole())) return resolveProperty(graph, grp);
842 throw new MissingVariableException("Unrecognized RVIPart: " + part, getPossibleRepresents(graph));
846 public Variable resolvePossible(ReadGraph graph, RVIPart part) throws DatabaseException {
847 if(part instanceof StringRVIPart) {
848 StringRVIPart srp = (StringRVIPart)part;
849 if(Role.CHILD.equals(srp.getRole())) return getPossibleChild(graph, srp.string);
850 else if(Role.PROPERTY.equals(srp.getRole())) return getPossibleProperty(graph, srp.string);
851 } else if(part instanceof ResourceRVIPart) {
852 ResourceRVIPart rrp = (ResourceRVIPart)part;
853 if(Role.CHILD.equals(rrp.getRole())) return resolvePossibleChild(graph, rrp.resource);
854 else if(Role.PROPERTY.equals(rrp.getRole())) return resolvePossibleProperty(graph, rrp.resource);
855 } else if(part instanceof GuidRVIPart) {
856 GuidRVIPart grp = (GuidRVIPart)part;
857 if(Role.CHILD.equals(grp.getRole())) return resolvePossibleChild(graph, grp);
858 else if(Role.PROPERTY.equals(grp.getRole())) return resolvePossibleProperty(graph, grp);
860 throw new MissingVariableException("Unrecognized RVIPart: " + part, getPossibleRepresents(graph));
864 public Datatype getDatatype(ReadGraph graph) throws DatabaseException {
865 throw new InvalidVariableException("No data type.");
868 public Binding getDefaultBinding(ReadGraph graph) throws DatabaseException {
869 Datatype type = getDatatype(graph);
870 return Bindings.getBinding(type);
873 public Binding getPossibleDefaultBinding(ReadGraph graph) throws DatabaseException {
875 return getDefaultBinding(graph);
876 } catch(DatabaseException e) {
882 public Datatype getPossibleDatatype(ReadGraph graph) throws DatabaseException {
884 return getDatatype(graph);
885 } catch(DatabaseException e) {
890 // public Binding getPossibleDefaultBinding(ReadGraph graph) throws DatabaseException {
892 // Datatype type = getPossibleDatatype(graph);
893 // if(type == null) return null;
894 // return Bindings.getBinding(type);
899 // public Datatype getPossibleDatatype(ReadGraph graph) throws DatabaseException {
901 // Variant vt = getVariantValue(graph);
902 // if(vt == null) return null;
903 // Binding binding = vt.getBinding();
904 // if(binding == null) return null;
905 // return binding.type();
910 public Variable getPredicate(ReadGraph graph) throws DatabaseException {
911 throw new MissingVariableException(getClass().getSimpleName() + ": No predicate property for " + getPossibleURI(graph), getPossibleRepresents(graph));
915 public Variable getPossiblePredicate(ReadGraph graph) throws DatabaseException {
917 return getPredicate(graph);
918 } catch(DatabaseException e) {
924 public Resource getPredicateResource(ReadGraph graph) throws DatabaseException {
925 Variable predicate = getPredicate(graph);
926 if (predicate == null)
927 throw new MissingVariableException(getClass().getSimpleName() + ": No predicate property for " + getPossibleURI(graph), getPossibleRepresents(graph));
928 return predicate.getRepresents(graph);
932 public Resource getPossiblePredicateResource(ReadGraph graph) throws DatabaseException {
933 Variable predicate = getPossiblePredicate(graph);
934 if(predicate == null) return null;
935 else return predicate.getPossibleRepresents(graph);
939 public Resource getPossibleRepresents(ReadGraph graph) throws DatabaseException {
941 return getRepresents(graph);
942 } catch(DatabaseException e) {
947 public Resource getType(ReadGraph graph) throws DatabaseException {
948 Resource typeFromFunction = getTypeFromPossibleTypeFunction(graph, Layer0.getInstance(graph).Entity, getPossibleTypeFunction(graph));
949 if (typeFromFunction != null)
950 return typeFromFunction;
952 Resource resource = getPossibleRepresents(graph);
953 if (resource == null) {
954 String uri = getPossiblePropertyValue(graph, "typeURI");
956 return graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri),
957 TransientCacheAsyncListener.<Resource> instance());
958 throw new DatabaseException("No type for " + getURI(graph));
960 return graph.getSingleType(resource);
964 public Resource getPossibleType(ReadGraph graph) throws DatabaseException {
966 Resource typeFromFunction = getTypeFromPossibleTypeFunction(graph, Layer0.getInstance(graph).Entity, getPossibleTypeFunction(graph));
967 if (typeFromFunction != null)
968 return typeFromFunction;
969 } catch (DatabaseException t) {
973 Resource resource = getPossibleRepresents(graph);
974 if (resource == null) {
975 String uri = getPossiblePropertyValue(graph, "typeURI");
977 return graph.syncRequest(new PossibleResource(uri), TransientCacheAsyncListener.<Resource> instance());
980 return graph.getPossibleObject(resource, Layer0.getInstance(graph).InstanceOf);
983 public Resource getType(ReadGraph graph, Resource baseType) throws DatabaseException {
984 Resource typeFromFunction = getTypeFromPossibleTypeFunction(graph, baseType, getPossibleTypeFunction(graph));
985 if (typeFromFunction != null)
986 return typeFromFunction;
988 Resource resource = getPossibleRepresents(graph);
989 if (resource == null) {
990 String uri = getPossiblePropertyValue(graph, "typeURI");
992 return graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri),
993 TransientCacheAsyncListener.<Resource> instance());
994 throw new DatabaseException("No type for " + getURI(graph));
996 return graph.getSingleType(resource, baseType);
1000 public Resource getPossibleType(ReadGraph graph, Resource baseType) throws DatabaseException {
1002 Resource typeFromFunction = getTypeFromPossibleTypeFunction(graph, baseType, getPossibleTypeFunction(graph));
1003 if (typeFromFunction != null)
1004 return typeFromFunction;
1005 } catch (DatabaseException t) {
1009 Resource resource = getPossibleRepresents(graph);
1010 if(resource == null) {
1011 String uri = getPossiblePropertyValue(graph, "typeURI");
1013 Resource type = graph.syncRequest(new PossibleResource(uri), TransientCacheAsyncListener.<Resource>instance());
1014 if(type == null) return null;
1015 if(graph.isInheritedFrom(type, baseType)) return type;
1020 return graph.getPossibleType(resource, baseType);
1023 private Resource getTypeFromPossibleTypeFunction(ReadGraph graph, Resource baseType,
1024 Function2<Variable, Resource, Resource> fn) throws DatabaseException {
1026 // Type function was not defined - return nothing
1029 SCLContext sclContext = SCLContext.getCurrent();
1030 Object oldGraph = sclContext.put("graph", graph);
1032 return (Resource) fn.apply(this, baseType);
1033 } catch (Throwable t) {
1034 if (t instanceof DatabaseException)
1035 throw (DatabaseException) t;
1036 throw new DatabaseException(t);
1038 sclContext.put("graph", oldGraph);
1042 @SuppressWarnings("unchecked")
1043 private Function2<Variable, Resource, Resource> getPossibleTypeFunction(ReadGraph graph) throws DatabaseException {
1044 Variable custom = getPossibleProperty(graph, "typeResource");
1045 return custom != null
1046 ? (Function2<Variable, Resource, Resource>) custom.getPossibleValue(graph)
1050 public Map<String, Variable> collectDomainProperties(ReadGraph graph, String classification, Map<String, Variable> map) throws DatabaseException {
1051 Map<String,Variable> all = collectDomainProperties(graph, null);
1052 for(Map.Entry<String, Variable> entry : all.entrySet()) {
1053 Set<String> classifications = entry.getValue().getClassifications(graph);
1054 if(classifications.contains(classification)) {
1055 if(map == null) map = new HashMap<String,Variable>();
1056 map.put(entry.getKey(), entry.getValue());
1063 public RVI getPossibleRVI(ReadGraph graph) throws DatabaseException {
1065 return getRVI(graph);
1066 } catch(DatabaseException e) {