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