X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=bundles%2Forg.simantics.db.layer0%2Fsrc%2Forg%2Fsimantics%2Fdb%2Flayer0%2FStandardNodeManager.java;h=c48c3f9d11983f333c78acdfb5e29d12b21011f5;hb=82ed7c74;hp=631d3a1a39dfbe88110dc0ef52942f536ebe50e1;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git 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 index 631d3a1a3..c48c3f9d1 100644 --- 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 @@ -1,386 +1,390 @@ -/******************************************************************************* - * 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> implements NodeManager { - - final private Node root; - final private StandardRealm 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 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 valueCache = new THashMap(); - protected THashMap> listeners = new THashMap>(); - - AtomicBoolean fireNodeListenersScheduled = new AtomicBoolean(false); - Runnable fireNodeListeners = new Runnable() { - @Override - public void run() { - fireNodeListenersScheduled.set(false); - final TObjectProcedure procedure = new TObjectProcedure() { - @Override - public boolean execute(Runnable object) { - object.run(); - return true; - } - }; - synchronized(listeners) { - listeners.forEachValue(new TObjectProcedure>() { - @Override - public boolean execute(THashSet object) { - object.forEach(procedure); - return true; - } - }); - } - } - }; - - Runnable clearValueCache = new Runnable() { - @Override - public void run() { - valueCache.clear(); - } - }; - - public StandardNodeManager(StandardRealm realm, Node root) { - this.realm = realm; - this.root = root; - } - - @Override - public List getChildNames(Node node) throws NodeManagerException { - List children = getChildren(node); - ArrayList names = new ArrayList(children.size()); - for(Node child : children) - names.add(getName(child)); - return names; - } - - @Override - public List getPropertyNames(Node node) throws NodeManagerException { - List properties = getProperties(node); - ArrayList names = new ArrayList(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 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 l = listeners.get(node); - if(l == null) { - l = new THashSet(); - listeners.put(node, l); - } - l.add(listener); - } - getRealm().asyncExec(listener); - } - - @Override - public void removeNodeListener(Node node, Runnable listener) { - synchronized(listeners) { - THashSet 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 map = realm.getEngine().getChildren(node); - return map.get(name); - } - - @Override - public Node getProperty(Node node, String name) throws NodeManagerException { - checkThreadAccess(); - Map map = realm.getEngine().getProperties(node); - return map.get(name); - } - - @Override - public List getChildren(Node node) throws NodeManagerException { - checkThreadAccess(); - return new ArrayList(realm.getEngine().getChildren(node).values()); - } - - @Override - public List getProperties(Node node) throws NodeManagerException { - checkThreadAccess(); - return new ArrayList(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; - } - -} +/******************************************************************************* + * 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> implements NodeManager { + + final private Node root; + final private StandardRealm 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 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 valueCache = new THashMap(); + protected THashMap> listeners = new THashMap>(); + + AtomicBoolean fireNodeListenersScheduled = new AtomicBoolean(false); + Runnable fireNodeListeners = new Runnable() { + @Override + public void run() { + fireNodeListenersScheduled.set(false); + final TObjectProcedure procedure = new TObjectProcedure() { + @Override + public boolean execute(Runnable object) { + object.run(); + return true; + } + }; + synchronized(listeners) { + listeners.forEachValue(new TObjectProcedure>() { + @Override + public boolean execute(THashSet object) { + object.forEach(procedure); + return true; + } + }); + } + } + }; + + Runnable clearValueCache = new Runnable() { + @Override + public void run() { + valueCache.clear(); + } + }; + + public StandardNodeManager(StandardRealm realm, Node root) { + this.realm = realm; + this.root = root; + } + + @Override + public List getChildNames(Node node) throws NodeManagerException { + List children = getChildren(node); + ArrayList names = new ArrayList(children.size()); + for(Node child : children) + names.add(getName(child)); + return names; + } + + @Override + public List getPropertyNames(Node node) throws NodeManagerException { + List properties = getProperties(node); + ArrayList names = new ArrayList(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 getStandardRealm() { + return realm; + } + + protected String getRealmId() { + return realm.getId(); + } + + 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 l = listeners.get(node); + if(l == null) { + l = new THashSet(); + listeners.put(node, l); + } + l.add(listener); + } + getRealm().asyncExec(listener); + } + + @Override + public void removeNodeListener(Node node, Runnable listener) { + synchronized(listeners) { + THashSet 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.getNodeManager().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 map = realm.getEngine().getChildren(node); + return map.get(name); + } + + @Override + public Node getProperty(Node node, String name) throws NodeManagerException { + checkThreadAccess(); + Map map = realm.getEngine().getProperties(node); + return map.get(name); + } + + @Override + public List getChildren(Node node) throws NodeManagerException { + checkThreadAccess(); + return new ArrayList(realm.getEngine().getChildren(node).values()); + } + + @Override + public List getProperties(Node node) throws NodeManagerException { + checkThreadAccess(); + return new ArrayList(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; + } + + public void clear() { + valueCache.clear(); + listeners.clear(); + } +}