]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/AbstractVariable.java
Do not compute replaceable type for non ReplaceableDefinedComponentTypes
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / variable / AbstractVariable.java
index d9366b132aa2a41e471bf0cd2ea7d1c9b19cef96..110ed2f777471aeef7e15128baa2381f3964d824 100644 (file)
@@ -39,6 +39,8 @@ import org.simantics.db.layer0.variable.RVI.ResourceRVIPart;
 import org.simantics.db.layer0.variable.RVI.StringRVIPart;
 import org.simantics.db.layer0.variable.Variables.Role;
 import org.simantics.layer0.Layer0;
+import org.simantics.scl.runtime.SCLContext;
+import org.simantics.scl.runtime.function.Function2;
 
 /**
  * Abstract implementation of Variable -interface.
@@ -80,7 +82,7 @@ public abstract class AbstractVariable implements Variable {
      
     @Override
     public PropertyInfo getPropertyInfo(ReadGraph graph) throws DatabaseException {
-       throw new DatabaseException("PropertyInfo is not available");
+       throw new InvalidVariableException("PropertyInfo is not available");
     }
     
     @Override
@@ -115,7 +117,7 @@ public abstract class AbstractVariable implements Variable {
                String name = child.getPossiblePropertyValue(graph, Variables.NAME, Bindings.STRING);
                if(rName.equals(name)) return child;
        }
-       throw new DatabaseException("Could not resolve child " + resource);
+       throw new MissingVariableException("Could not resolve child " + rName, resource);
     }
     
     protected Variable resolveChild(ReadGraph graph, GuidRVIPart part) throws DatabaseException {
@@ -128,7 +130,7 @@ public abstract class AbstractVariable implements Variable {
                String name = child.getPossiblePropertyValue(graph, Variables.NAME, Bindings.STRING);
                if(rName.equals(name)) return child;
        }
-       throw new DatabaseException("Could not resolve child " + resource);
+       throw new MissingVariableException("Could not resolve child " + rName, resource);
     }
 
     protected Variable resolveProperty(ReadGraph graph, GuidRVIPart part) throws DatabaseException {
@@ -187,18 +189,6 @@ public abstract class AbstractVariable implements Variable {
                return graph.getPossibleRelatedValue2(represents, graph.getService(Layer0.class).HasLabel, getParent(graph), Bindings.STRING);
     }
 
-    public Resource getType(ReadGraph graph) throws DatabaseException {
-       
-        Resource resource = getPossibleRepresents(graph);
-        if(resource == null) {
-               String uri = getPossiblePropertyValue(graph, "typeURI");
-               if(uri != null) return graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri), TransientCacheAsyncListener.<Resource>instance());
-            throw new DatabaseException("No type for " + getURI(graph));
-        }
-        return graph.getSingleType(resource);
-        
-    }
-    
     public RVIPart getRVIPart(ReadGraph graph) throws DatabaseException {
         throw new UnsupportedOperationException();
     }
@@ -213,7 +203,7 @@ public abstract class AbstractVariable implements Variable {
                Variable parent = getParent(graph);
                if (parent == null)
                        // TODO: consider using a more suitable exception here to better convey the situation.
-                       throw new MissingVariableException("no parent for variable " + this + " (URI=" + getPossibleURI(graph) + ")");
+                       throw new MissingVariableException("no parent for variable " + this + " (URI=" + getPossibleURI(graph) + ")", getPossibleRepresents(graph));
                RVI base = graph.syncRequest(new VariableRVIRequest(parent));
                RVIPart part = getRVIPart(graph);
                return new RVIBuilder(base).append(part).toRVI();
@@ -223,7 +213,7 @@ public abstract class AbstractVariable implements Variable {
     protected Variable getDomainProperty(ReadGraph graph, String name) throws DatabaseException {
         Variable property = getPossibleDomainProperty(graph, name);
         if(property == null)
-            throw new MissingVariableException(getIdentifier() + ": Didn't find property " + name + ".");
+            throw new MissingVariableException(getIdentifier() + ": Didn't find property " + name + ".", getPossibleRepresents(graph));
         return property;
     }
     
@@ -470,17 +460,20 @@ public abstract class AbstractVariable implements Variable {
 
     @SuppressWarnings("unchecked")
     @Override
-    public <T> T getPropertyValue(ReadGraph graph, String name, Binding binding)
-            throws DatabaseException {
-        if(binding instanceof StringBinding) {
-            StringBinding sb = (StringBinding)binding;
+    public <T> T getPropertyValue(ReadGraph graph, String name, Binding binding) throws DatabaseException {
+        if (binding instanceof StringBinding) {
+            StringBinding sb = (StringBinding) binding;
             try {
-                if(Variables.NAME.equals(name)) return (T)sb.create((String)checkNull(graph, getName(graph)));
-                if(Variables.LABEL.equals(name)) return (T)sb.create((String)checkNull(graph, getLabel(graph)));
-                if(Variables.URI.equals(name)) return (T)sb.create((String)checkNull(graph, getURI(graph)));
-//                if(Variables.SERIALISED.equals(name)) return (T)sb.create((String)checkNull(graph, getSerialized(graph)));
-            } catch(BindingException e) {
-                throw new DatabaseException(e);
+                if (Variables.NAME.equals(name))
+                    return (T) sb.create((String) checkNull(graph, getName(graph)));
+                if (Variables.LABEL.equals(name))
+                    return (T) sb.create((String) checkNull(graph, getLabel(graph)));
+                if (Variables.URI.equals(name))
+                    return (T) sb.create((String) checkNull(graph, getURI(graph)));
+                // if(Variables.SERIALISED.equals(name)) return
+                // (T)sb.create((String)checkNull(graph, getSerialized(graph)));
+            } catch (BindingException e) {
+                throw new org.simantics.db.exception.BindingException("Could not get value for property " + name + " with binding " + binding, e);
             }
         }
         Variable property = getPossibleExtraProperty(graph, name);
@@ -488,7 +481,7 @@ public abstract class AbstractVariable implements Variable {
             return property.getValue(graph, binding);
         property = getPossibleDomainProperty(graph, name);
         if(property == null)
-            throw new MissingVariableException("Didn't find property " + name + " for " + this + ".");
+            throw new MissingVariableException("Didn't find property " + name + " for " + this + ".", getPossibleRepresents(graph));
         return property.getValue(graph, binding);
     }
 
@@ -509,7 +502,7 @@ public abstract class AbstractVariable implements Variable {
                 if(Variables.URI.equals(name)) return (T)sb.create((String)getURI(graph));
 //                if(Variables.SERIALISED.equals(name)) return (T)sb.create((String)getSerialized(graph));
             } catch(BindingException e) {
-                throw new DatabaseException(e);
+                throw new org.simantics.db.exception.BindingException("Could not get property value for " + name + " with binding " + binding, e);
             }
         }
         Variable property = getPossibleExtraProperty(graph, name);
@@ -531,7 +524,7 @@ public abstract class AbstractVariable implements Variable {
        try {
                        setValue(graph, value, Bindings.getBinding(value.getClass()));
                } catch (BindingConstructionException e) {
-                       throw new DatabaseException(e);
+                       throw new org.simantics.db.exception.BindingException("Could not set " + String.valueOf(value) + " value for " + getRepresents(graph), e);
                }
     }
     
@@ -561,7 +554,7 @@ public abstract class AbstractVariable implements Variable {
             throws DatabaseException {
         Variable child = getPossibleChild(graph, name);
         if(child == null)
-            throw new MissingVariableException(getURI(graph) + ": didn't find child " + name + " for " + getIdentifier() + ".");
+            throw new MissingVariableException(getURI(graph) + ": didn't find child " + name + " for " + getIdentifier() + ".", getPossibleRepresents(graph));
         return child;
     }    
 
@@ -569,7 +562,7 @@ public abstract class AbstractVariable implements Variable {
     public Variable getProperty(ReadGraph graph, String name)  throws DatabaseException {
         Variable result = getPossibleProperty(graph, name);
         if(result == null)
-            throw new MissingVariableException(getClass().getSimpleName() + ": Didn't find property " + name + " for " + getPossibleURI(graph) + ".");
+            throw new MissingVariableException(getClass().getSimpleName() + ": Didn't find property " + name + " for " + getPossibleURI(graph) + ".", getPossibleRepresents(graph));
         return result;
     }
     
@@ -588,7 +581,7 @@ public abstract class AbstractVariable implements Variable {
         case '.': {
             Variable parent = getParent(graph); 
             if(parent == null)
-                throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").");
+                throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").", getPossibleRepresents(graph));
             return parent.browse(graph, suffix.substring(1));
         }
         case '#': {
@@ -596,7 +589,7 @@ public abstract class AbstractVariable implements Variable {
             Variable property = getProperty(graph, 
                     decodeString(suffix.substring(1, segmentEnd)));
             if(property == null) 
-                throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").");
+                throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").", getPossibleRepresents(graph));
             return property.browse(graph, suffix.substring(segmentEnd));
         }
         case '/': {
@@ -604,11 +597,11 @@ public abstract class AbstractVariable implements Variable {
             Variable child = getChild(graph, 
                     decodeString(suffix.substring(1, segmentEnd)));
             if(child == null) 
-                throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").");
+                throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").", getPossibleRepresents(graph));
             return child.browse(graph, suffix.substring(segmentEnd));
         }
         default:
-            throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").");
+            throw new MissingVariableException("Didn't find " + suffix + " for " + this + " (" + getPossibleURI(graph) + ").", getPossibleRepresents(graph));
         }
        
     }
@@ -662,7 +655,7 @@ public abstract class AbstractVariable implements Variable {
         Variable variable = browsePossible(graph, config);
         if(variable == null)
             throw new MissingVariableException("Didn't find a variable related to " + 
-                    NameUtils.getSafeName(graph, config) + ".");
+                    NameUtils.getSafeName(graph, config) + ".", config);
         return variable;
     }
 
@@ -732,7 +725,7 @@ public abstract class AbstractVariable implements Variable {
                try {
                                binding = Bindings.OBJECT.getContentBinding(value);
                        } catch (BindingException e) {
-                               throw new DatabaseException(e);
+                               throw new org.simantics.db.exception.BindingException("Could not bind variant value " + String.valueOf(value) + " for " + getRepresents(graph), e);
                        }
                return new Variant(binding, value);
         }
@@ -846,7 +839,7 @@ public abstract class AbstractVariable implements Variable {
                        if(Role.CHILD.equals(grp.getRole())) return resolveChild(graph, grp);
                        else if(Role.PROPERTY.equals(grp.getRole())) return resolveProperty(graph, grp);
                }
-               throw new DatabaseException("Unrecognized RVIPart: " + part);
+               throw new MissingVariableException("Unrecognized RVIPart: " + part, getPossibleRepresents(graph));
        }
 
        @Override
@@ -864,12 +857,12 @@ public abstract class AbstractVariable implements Variable {
                        if(Role.CHILD.equals(grp.getRole())) return resolvePossibleChild(graph, grp);
                        else if(Role.PROPERTY.equals(grp.getRole())) return resolvePossibleProperty(graph, grp);
                }
-               throw new DatabaseException("Unrecognized RVIPart: " + part);
+               throw new MissingVariableException("Unrecognized RVIPart: " + part, getPossibleRepresents(graph));
        }
 
        @Override
        public Datatype getDatatype(ReadGraph graph) throws DatabaseException {
-               throw new DatabaseException("No data type.");
+               throw new InvalidVariableException("No data type.");
        }
 
        public Binding getDefaultBinding(ReadGraph graph) throws DatabaseException {
@@ -915,7 +908,7 @@ public abstract class AbstractVariable implements Variable {
 
        @Override
        public Variable getPredicate(ReadGraph graph) throws DatabaseException {
-               throw new DatabaseException(getClass().getSimpleName() + ": No predicate property for " + getPossibleURI(graph));
+               throw new MissingVariableException(getClass().getSimpleName() + ": No predicate property for " + getPossibleURI(graph), getPossibleRepresents(graph));
        }
 
        @Override
@@ -926,14 +919,15 @@ public abstract class AbstractVariable implements Variable {
             return null;
         }
        }
-       
-       @Override
-       public Resource getPredicateResource(ReadGraph graph) throws DatabaseException {
-               Variable predicate = getPredicate(graph);
-               if(predicate == null) throw new DatabaseException(getClass().getSimpleName() + ": No predicate property for " + getPossibleURI(graph));
-               return predicate.getRepresents(graph);
-       }
-       
+
+    @Override
+    public Resource getPredicateResource(ReadGraph graph) throws DatabaseException {
+        Variable predicate = getPredicate(graph);
+        if (predicate == null)
+            throw new MissingVariableException(getClass().getSimpleName() + ": No predicate property for " + getPossibleURI(graph), getPossibleRepresents(graph));
+        return predicate.getRepresents(graph);
+    }
+
        @Override
        public Resource getPossiblePredicateResource(ReadGraph graph) throws DatabaseException {
                Variable predicate = getPossiblePredicate(graph);
@@ -950,42 +944,108 @@ public abstract class AbstractVariable implements Variable {
         }
        }
 
-       @Override
-       public Resource getPossibleType(ReadGraph graph) throws DatabaseException {
+    public Resource getType(ReadGraph graph) throws DatabaseException {
+        Resource typeFromFunction = getTypeFromPossibleTypeFunction(graph, Layer0.getInstance(graph).Entity, getPossibleTypeFunction(graph));
+        if (typeFromFunction != null)
+            return typeFromFunction;
+
         Resource resource = getPossibleRepresents(graph);
-        if(resource == null) {
-               String uri = getPossiblePropertyValue(graph, "typeURI");
-               if(uri != null) return graph.syncRequest(new PossibleResource(uri), TransientCacheAsyncListener.<Resource>instance());
+        if (resource == null) {
+            String uri = getPossiblePropertyValue(graph, "typeURI");
+            if (uri != null)
+                return graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri),
+                        TransientCacheAsyncListener.<Resource> instance());
+            throw new DatabaseException("No type for " + getURI(graph));
+        }
+        return graph.getSingleType(resource);
+    }
+
+    @Override
+    public Resource getPossibleType(ReadGraph graph) throws DatabaseException {
+        try {
+            Resource typeFromFunction = getTypeFromPossibleTypeFunction(graph, Layer0.getInstance(graph).Entity, getPossibleTypeFunction(graph));
+            if (typeFromFunction != null)
+                return typeFromFunction;
+        } catch (DatabaseException t) {
+            return null;
+        }
+
+        Resource resource = getPossibleRepresents(graph);
+        if (resource == null) {
+            String uri = getPossiblePropertyValue(graph, "typeURI");
+            if (uri != null)
+                return graph.syncRequest(new PossibleResource(uri), TransientCacheAsyncListener.<Resource> instance());
             return null;
         }
         return graph.getPossibleObject(resource, Layer0.getInstance(graph).InstanceOf);
-       }
+    }
 
     public Resource getType(ReadGraph graph, Resource baseType) throws DatabaseException {
+        Resource typeFromFunction = getTypeFromPossibleTypeFunction(graph, baseType, getPossibleTypeFunction(graph));
+        if (typeFromFunction != null)
+            return typeFromFunction;
+
         Resource resource = getPossibleRepresents(graph);
-        if(resource == null) {
-               String uri = getPossiblePropertyValue(graph, "typeURI");
-               if(uri != null) return graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri), TransientCacheAsyncListener.<Resource>instance());
+        if (resource == null) {
+            String uri = getPossiblePropertyValue(graph, "typeURI");
+            if (uri != null)
+                return graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri),
+                        TransientCacheAsyncListener.<Resource> instance());
             throw new DatabaseException("No type for " + getURI(graph));
         }
         return graph.getSingleType(resource, baseType);
     }
 
-       @Override
-       public Resource getPossibleType(ReadGraph graph, Resource baseType) throws DatabaseException {
+    @Override
+    public Resource getPossibleType(ReadGraph graph, Resource baseType) throws DatabaseException {
+        try {
+            Resource typeFromFunction = getTypeFromPossibleTypeFunction(graph, baseType, getPossibleTypeFunction(graph));
+            if (typeFromFunction != null)
+                return typeFromFunction;
+        } catch (DatabaseException t) {
+            return null;
+        }
+
         Resource resource = getPossibleRepresents(graph);
         if(resource == null) {
-               String uri = getPossiblePropertyValue(graph, "typeURI");
-               if(uri != null) {
-                       Resource type = graph.syncRequest(new PossibleResource(uri), TransientCacheAsyncListener.<Resource>instance());
-                       if(type == null) return null;
-                       if(graph.isInheritedFrom(type, baseType)) return type;
-                       else return null;
-               }
+            String uri = getPossiblePropertyValue(graph, "typeURI");
+            if(uri != null) {
+                Resource type = graph.syncRequest(new PossibleResource(uri), TransientCacheAsyncListener.<Resource>instance());
+                if(type == null) return null;
+                if(graph.isInheritedFrom(type, baseType)) return type;
+                else return null;
+            }
             return null;
         }
         return graph.getPossibleType(resource, baseType);
-       }
+    }
+
+    private Resource getTypeFromPossibleTypeFunction(ReadGraph graph, Resource baseType,
+            Function2<Variable, Resource, Resource> fn) throws DatabaseException {
+        if (fn == null)
+            // Type function was not defined - return nothing
+            return null;
+
+        SCLContext sclContext = SCLContext.getCurrent();
+        Object oldGraph = sclContext.put("graph", graph);
+        try {
+            return (Resource) fn.apply(this, baseType);
+        } catch (Throwable t) {
+            if (t instanceof DatabaseException)
+                throw (DatabaseException) t;
+            throw new DatabaseException(t);
+        } finally {
+            sclContext.put("graph", oldGraph);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private Function2<Variable, Resource, Resource> getPossibleTypeFunction(ReadGraph graph) throws DatabaseException {
+        Variable custom = getPossibleProperty(graph, "typeResource");
+        return custom != null
+            ? (Function2<Variable, Resource, Resource>) custom.getPossibleValue(graph)
+            : null;
+    }
 
     public Map<String, Variable> collectDomainProperties(ReadGraph graph, String classification, Map<String, Variable> map) throws DatabaseException {
        Map<String,Variable> all = collectDomainProperties(graph, null);