]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardNodeManager.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / StandardNodeManager.java
diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardNodeManager.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardNodeManager.java
new file mode 100644 (file)
index 0000000..631d3a1
--- /dev/null
@@ -0,0 +1,386 @@
+/*******************************************************************************\r
+ * Copyright (c) 2013 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *     Semantum Oy - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.db.layer0;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.concurrent.atomic.AtomicBoolean;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.VariantBinding;\r
+import org.simantics.databoard.binding.error.BindingConstructionException;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
+import org.simantics.databoard.type.Datatype;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.simulator.variable.NodeManager;\r
+import org.simantics.simulator.variable.Realm;\r
+import org.simantics.simulator.variable.exceptions.NoSuchNodeException;\r
+import org.simantics.simulator.variable.exceptions.NodeManagerException;\r
+import org.simantics.simulator.variable.exceptions.NotInRealmException;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.procedure.TObjectProcedure;\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+/**\r
+ * StandardNodeManager gives default implementations to some methods\r
+ * of NodeManager.\r
+ * \r
+ * @author Antti Villberg\r
+ */\r
+public abstract class StandardNodeManager<Node,Engine extends StandardEngine<Node>> implements NodeManager<Node> {\r
+       \r
+       final private Node root;\r
+       final private StandardRealm<Node,Engine> realm;\r
+\r
+    final static Binding NO_BINDING = new VariantBinding() {\r
+\r
+        @Override\r
+        public Object getContent(Object variant, Binding contentBinding) throws BindingException {\r
+            throw new Error();\r
+        }\r
+\r
+        @Override\r
+        public Object getContent(Object variant) throws BindingException {\r
+            throw new Error();\r
+        }\r
+\r
+        @Override\r
+        public Datatype getContentType(Object variant) throws BindingException {\r
+            throw new Error();\r
+        }\r
+\r
+        @Override\r
+        public Binding getContentBinding(Object variant) throws BindingException {\r
+            throw new Error();\r
+        }\r
+\r
+        @Override\r
+        public Object create(Binding contentBinding, Object content) throws BindingException {\r
+            throw new Error();\r
+        }\r
+\r
+        @Override\r
+        public void setContent(Object variant, Binding contentBinding, Object content) throws BindingException {\r
+            throw new Error();\r
+        }\r
+\r
+        @Override\r
+        public boolean isInstance(Object obj) {\r
+            return true;\r
+        }\r
+\r
+        @Override\r
+        public void assertInstaceIsValid(Object obj, Set<Object> validInstances) throws BindingException {\r
+            throw new Error();\r
+        }\r
+        \r
+        @Override\r
+        public int compare(Object o1, Object o2) throws org.simantics.databoard.binding.error.RuntimeBindingException {\r
+               if(o1 == null) {\r
+                       if(o2 == null) {\r
+                               return 0;\r
+                       } else {\r
+                               return  - System.identityHashCode(o2);\r
+                       }\r
+               } else {\r
+                       if(o2 == null) {\r
+                               return  System.identityHashCode(o1);\r
+                       } else {\r
+                               if(o1.equals(o2)) return 0;\r
+                               return System.identityHashCode(o1) - System.identityHashCode(o2);       \r
+                       }\r
+               }\r
+        }\r
+\r
+    };\r
+    \r
+    THashMap<Node, Object> valueCache = new THashMap<Node, Object>(); \r
+    protected THashMap<Node, THashSet<Runnable>> listeners = new THashMap<Node, THashSet<Runnable>>(); \r
+    \r
+    AtomicBoolean fireNodeListenersScheduled = new AtomicBoolean(false);\r
+    Runnable fireNodeListeners = new Runnable() {\r
+        @Override\r
+        public void run() {\r
+            fireNodeListenersScheduled.set(false);\r
+            final TObjectProcedure<Runnable> procedure = new TObjectProcedure<Runnable>() {\r
+                @Override\r
+                public boolean execute(Runnable object) {\r
+                    object.run();\r
+                    return true;\r
+                }\r
+            };\r
+            synchronized(listeners) {\r
+                listeners.forEachValue(new TObjectProcedure<THashSet<Runnable>>() {\r
+                    @Override\r
+                    public boolean execute(THashSet<Runnable> object) {\r
+                        object.forEach(procedure);\r
+                        return true;\r
+                    }\r
+                });\r
+            }\r
+        }\r
+    };\r
+    \r
+    Runnable clearValueCache = new Runnable() {\r
+        @Override\r
+        public void run() {\r
+            valueCache.clear(); \r
+        }\r
+    };\r
+    \r
+    public StandardNodeManager(StandardRealm<Node,Engine> realm, Node root) {\r
+       this.realm = realm;\r
+       this.root = root;\r
+       }\r
+    \r
+       @Override\r
+       public List<String> getChildNames(Node node) throws NodeManagerException {\r
+               List<Node> children = getChildren(node);\r
+               ArrayList<String> names = new ArrayList<String>(children.size());\r
+               for(Node child : children)\r
+                       names.add(getName(child));\r
+               return names;\r
+       }\r
+       \r
+       @Override\r
+       public List<String> getPropertyNames(Node node) throws NodeManagerException {\r
+               List<Node> properties = getProperties(node);\r
+               ArrayList<String> names = new ArrayList<String>(properties.size());\r
+               for(Node property : properties)\r
+                       names.add(getName(property));\r
+               return names;\r
+       }\r
+       \r
+       @Override\r
+       public Object getValue(Node node, String propertyName, Binding binding)\r
+                       throws NodeManagerException, BindingException {\r
+               Node property = getProperty(node, propertyName);\r
+               if(property == null)\r
+                       throw new NoSuchNodeException("Didn't find a property " + propertyName);\r
+               return getValue(property, binding);\r
+       }\r
+       \r
+       @Override\r
+       public void setValue(Node node, String propertyName, Object value,\r
+                       Binding binding) throws NodeManagerException, BindingException {\r
+               Node property = getProperty(node, propertyName);\r
+               if(property == null)\r
+                       throw new NoSuchNodeException("Didn't find a property " + propertyName);\r
+               setValue(property, value, binding);\r
+       }\r
+       \r
+       @Override\r
+       public Variant getValue(Node node) throws NodeManagerException {\r
+               Object value = getEngineValueOrCached(node);\r
+               if (value instanceof Variant)\r
+                   return (Variant) value;\r
+        try {\r
+            Binding binding = Bindings.getBinding(value.getClass());\r
+            return new Variant(binding, value);\r
+        } catch (BindingConstructionException e) {\r
+            e.printStackTrace();\r
+            return null;\r
+        }\r
+       }\r
+       \r
+       @Override\r
+       public Variant getValue(Node node, String propertyName)\r
+                       throws NodeManagerException {\r
+               Node property = getProperty(node, propertyName);\r
+               if(property == null)\r
+                       throw new NoSuchNodeException("Didn't find a property " + propertyName);\r
+               return getValue(property);\r
+       }\r
+       \r
+    @Override\r
+    public String getPropertyURI(Node parent, Node property) {\r
+        return null;\r
+    }\r
+    \r
+    @Override\r
+    public Realm getRealm() {\r
+       return realm;\r
+    }\r
+    \r
+    public StandardRealm<Node, Engine> getStandardRealm() {\r
+       return realm;\r
+    }\r
+    \r
+    protected String getRealmId() {\r
+       return realm.id;\r
+    }\r
+    \r
+    public Node getRoot() {\r
+       return root;\r
+    }\r
+    \r
+    protected boolean isRoot(Node node) {\r
+       return root.equals(node);\r
+    }\r
+\r
+    @Override\r
+    public void addNodeListener(Node node, Runnable listener) {\r
+        synchronized(listeners) {\r
+            THashSet<Runnable> l = listeners.get(node);\r
+            if(l == null) {\r
+                l = new THashSet<Runnable>();\r
+                listeners.put(node, l);\r
+            }\r
+            l.add(listener);\r
+        }\r
+        getRealm().asyncExec(listener);\r
+    }\r
+\r
+    @Override\r
+    public void removeNodeListener(Node node, Runnable listener) {\r
+        synchronized(listeners) {\r
+            THashSet<Runnable> l = listeners.get(node);\r
+            if(l != null) {\r
+                l.remove(listener);\r
+                if(l.isEmpty())\r
+                    listeners.remove(node);\r
+            }\r
+        }\r
+    }\r
+    \r
+    public void fireNodeListeners() {\r
+        if(!fireNodeListenersScheduled.getAndSet(true))\r
+            realm.asyncExec(fireNodeListeners);\r
+    }\r
+    \r
+    public void fireNodeListenersSync() {\r
+       try {\r
+                       realm.syncExec(fireNodeListeners);\r
+               } catch (InterruptedException e) {\r
+                       e.printStackTrace();\r
+               }\r
+    }\r
+\r
+    public void refreshVariables() {\r
+        realm.asyncExec(clearValueCache);\r
+        fireNodeListeners();\r
+    }\r
+\r
+    public void refreshVariablesSync() {\r
+        try {\r
+                       realm.syncExec(clearValueCache);\r
+               } catch (InterruptedException e) {\r
+                       e.printStackTrace();\r
+               }\r
+        fireNodeListenersSync();\r
+    }\r
+    \r
+    protected Object getEngineValueOrCached(Node node) throws NodeManagerException {\r
+        Object value = valueCache.get(node);\r
+        if(value == null) {\r
+               value = realm.getEngine().getValue(node);\r
+            valueCache.put(node, value);\r
+        }\r
+        return value;\r
+    }\r
+    \r
+\r
+    @Override\r
+    public Object getValue(Node node, Binding binding) throws NodeManagerException {\r
+        checkThreadAccess();\r
+        return getEngineValueOrCached(node);\r
+    }\r
+\r
+    protected void checkThreadAccess() throws NodeManagerException {\r
+        if(Thread.currentThread() != realm.getThread())\r
+            throw new NotInRealmException();\r
+    }\r
+    \r
+    protected Datatype getDatatypeForValue(Object value) throws DatabaseException {\r
+       Binding binding = Bindings.getBindingUnchecked(value.getClass());\r
+       if(binding == null) return null;\r
+       else return binding.type();\r
+    }\r
+    \r
+    @Override\r
+    public void setValue(Node node, Object value, Binding binding)\r
+            throws NodeManagerException {\r
+       checkThreadAccess();\r
+       valueCache.put(node, value);\r
+       realm.getEngine().setValue(node, value);\r
+       realm.nodeManager.valueCache.put(node, value);\r
+       refreshVariables();\r
+    }\r
+    \r
+    @Override\r
+    public String getName(Node node) {\r
+        if(isRoot(node)) {\r
+               String id = getRealmId();\r
+               int lastSlash = id.lastIndexOf("/");\r
+               if(lastSlash == -1) throw new IllegalStateException("Invalid realm id " + id);\r
+               String name = id.substring(lastSlash+1); \r
+               return name;\r
+        } else {\r
+               return realm.getEngine().getName(node);\r
+        }\r
+    }\r
+    \r
+\r
+    @Override\r
+    public Node getNode(String path) throws NodeManagerException {\r
+        checkThreadAccess();\r
+        throw new UnsupportedOperationException();\r
+    }\r
+    \r
+    @Override\r
+    public Node getChild(Node node, String name) throws NodeManagerException {\r
+        checkThreadAccess();\r
+       Map<String,Node> map = realm.getEngine().getChildren(node);\r
+       return map.get(name);\r
+    }\r
+\r
+    @Override\r
+    public Node getProperty(Node node, String name) throws NodeManagerException {\r
+       checkThreadAccess();\r
+       Map<String,Node> map = realm.getEngine().getProperties(node);\r
+       return map.get(name);\r
+    }\r
+\r
+    @Override\r
+    public List<Node> getChildren(Node node) throws NodeManagerException {\r
+        checkThreadAccess();\r
+        return new ArrayList<Node>(realm.getEngine().getChildren(node).values());\r
+    }\r
+\r
+    @Override\r
+    public List<Node> getProperties(Node node) throws NodeManagerException {\r
+        checkThreadAccess();\r
+        return new ArrayList<Node>(realm.getEngine().getProperties(node).values());\r
+    }\r
+\r
+    @Override\r
+    public Datatype getDatatype(Node node) throws NodeManagerException {\r
+        checkThreadAccess();\r
+        try {\r
+            Datatype type = getDatatypeForValue(getEngineValueOrCached(node));\r
+            return type;\r
+        } catch (DatabaseException e) {\r
+            e.printStackTrace();\r
+        } catch (RuntimeBindingConstructionException e) {\r
+            // There is no datatype for all values\r
+        }\r
+        return null;\r
+    }\r
+    \r
+}\r