1 package org.simantics.modeling.scl;
\r
3 import java.util.ArrayList;
\r
4 import java.util.Collections;
\r
5 import java.util.List;
\r
6 import java.util.Set;
\r
7 import java.util.concurrent.atomic.AtomicBoolean;
\r
9 import org.simantics.databoard.Datatypes;
\r
10 import org.simantics.databoard.binding.Binding;
\r
11 import org.simantics.databoard.type.Datatype;
\r
12 import org.simantics.db.exception.DatabaseException;
\r
13 import org.simantics.db.layer0.variable.NodeSupport;
\r
14 import org.simantics.scl.compiler.types.Type;
\r
15 import org.simantics.simulator.variable.Realm;
\r
16 import org.simantics.simulator.variable.exceptions.NodeManagerException;
\r
17 import org.simantics.simulator.variable.exceptions.NotInRealmException;
\r
18 import org.simantics.simulator.variable.impl.AbstractNodeManager;
\r
19 import org.simantics.structural.stubs.StructuralResource2;
\r
21 import gnu.trove.map.hash.THashMap;
\r
22 import gnu.trove.procedure.TObjectProcedure;
\r
23 import gnu.trove.set.hash.THashSet;
\r
25 public class SCLNodeManager extends AbstractNodeManager<String> {
\r
27 public static final String ROOT = "@";
\r
30 THashMap<String, Object> valueCache = new THashMap<String, Object>();
\r
31 THashMap<String, THashSet<Runnable>> listeners = new THashMap<String, THashSet<Runnable>>();
\r
33 AtomicBoolean fireNodeListenersScheduled = new AtomicBoolean(false);
\r
34 Runnable fireNodeListeners = new Runnable() {
\r
37 fireNodeListenersScheduled.set(false);
\r
38 final TObjectProcedure<Runnable> procedure = new TObjectProcedure<Runnable>() {
\r
40 public boolean execute(Runnable object) {
\r
45 synchronized(listeners) {
\r
46 listeners.forEachValue(new TObjectProcedure<THashSet<Runnable>>() {
\r
48 public boolean execute(THashSet<Runnable> object) {
\r
49 object.forEach(procedure);
\r
57 Runnable clearValueCache = new Runnable() {
\r
60 valueCache.clear();
\r
64 public SCLNodeManager(SCLRealm realm) {
\r
70 public Realm getRealm() {
\r
74 public String getRoot() {
\r
79 public String getName(String node) {
\r
80 if(ROOT.equals(node)) {
\r
81 String id = realm.id;
\r
82 int lastSlash = id.lastIndexOf("/");
\r
83 if(lastSlash == -1) throw new IllegalStateException("Invalid realm id " + id);
\r
84 String name = id.substring(lastSlash+1);
\r
91 public void addNodeListener(String node, Runnable listener) {
\r
92 synchronized(listeners) {
\r
93 THashSet<Runnable> l = listeners.get(node);
\r
95 l = new THashSet<Runnable>();
\r
96 listeners.put(node, l);
\r
100 realm.asyncExec(listener);
\r
104 public void removeNodeListener(String node, Runnable listener) {
\r
105 synchronized(listeners) {
\r
106 THashSet<Runnable> l = listeners.get(node);
\r
108 l.remove(listener);
\r
110 listeners.remove(node);
\r
115 public void fireNodeListeners() {
\r
116 if(!fireNodeListenersScheduled.getAndSet(true))
\r
117 realm.asyncExec(fireNodeListeners);
\r
120 public void fireNodeListenersSync() {
\r
122 realm.syncExec(fireNodeListeners);
\r
123 } catch (InterruptedException e) {
\r
124 e.printStackTrace();
\r
128 public void refreshVariables() {
\r
129 realm.asyncExec(clearValueCache);
\r
130 fireNodeListeners();
\r
133 public void refreshVariablesSync() {
\r
135 realm.syncExec(clearValueCache);
\r
136 } catch (InterruptedException e) {
\r
137 e.printStackTrace();
\r
139 fireNodeListenersSync();
\r
143 public String getNode(String path) throws NodeManagerException {
\r
144 checkThreadAccess();
\r
145 throw new UnsupportedOperationException();
\r
149 public String getChild(String node, String name)
\r
150 throws NodeManagerException {
\r
151 checkThreadAccess();
\r
156 public String getProperty(String node, String name)
\r
157 throws NodeManagerException {
\r
158 checkThreadAccess();
\r
159 if(node.equals(ROOT))
\r
166 public List<String> getChildren(String node) throws NodeManagerException {
\r
167 checkThreadAccess();
\r
168 return Collections.emptyList();
\r
172 public List<String> getProperties(String node) throws NodeManagerException {
\r
173 checkThreadAccess();
\r
174 if(!node.equals(ROOT))
\r
175 return Collections.emptyList();
\r
177 Set<String> variables = realm.getConnection().getVariables();
\r
178 return new ArrayList<String>(variables);
\r
183 public Datatype getDatatype(String node) throws NodeManagerException {
\r
184 checkThreadAccess();
\r
186 Datatype type = getDatatypeForValue(getSCLValue(node));
\r
188 } catch (DatabaseException e) {
\r
189 e.printStackTrace();
\r
195 public Object getValue(String node, Binding binding) throws NodeManagerException {
\r
196 checkThreadAccess();
\r
197 return getSCLValue(node);
\r
201 private Type getType(String name) {
\r
202 return realm.getConnection().getVariableType(name);
\r
205 private Datatype getDatatypeForValue(Object value) throws DatabaseException {
\r
206 if(value instanceof Double) return Datatypes.DOUBLE;
\r
207 if(value instanceof Float) return Datatypes.FLOAT;
\r
208 if(value instanceof Integer) return Datatypes.INTEGER;
\r
209 if(value instanceof Long) return Datatypes.LONG;
\r
210 if(value instanceof String) return Datatypes.STRING;
\r
211 if(value instanceof Boolean) return Datatypes.BOOLEAN;
\r
213 if (value instanceof List) return null;
\r
215 if (value instanceof Object) return null;
\r
217 if (value == null) return null;
\r
219 else throw new DatabaseException("No Datatype for value " + value);
\r
223 public void setValue(String node, Object value, Binding binding)
\r
224 throws NodeManagerException {
\r
225 checkThreadAccess();
\r
226 valueCache.put(node, value);
\r
227 realm.getConnection().setVariable(node, getType(node), value);
\r
228 realm.nodeManager.valueCache.put(node, value);
\r
229 refreshVariables();
\r
232 public void setValue(String node, Type type, Object value)
\r
233 throws NodeManagerException {
\r
235 checkThreadAccess();
\r
236 valueCache.put(node, value);
\r
237 realm.getConnection().setVariable(node, type, value);
\r
239 NodeSupport support = SCLSessionManager.getOrCreateNodeSupport(realm.getId());
\r
240 support.structureCache.put(ROOT, null);
\r
241 support.valueCache.put(node, null);
\r
243 realm.nodeManager.valueCache.put(node, value);
\r
245 refreshVariables();
\r
248 static final Set<String> COMPONENT_CLASS = Collections.singleton(StructuralResource2.URIs.Component);
\r
251 public Set<String> getClassifications(String node) throws NodeManagerException {
\r
252 checkThreadAccess();
\r
253 if(node.equals(ROOT))
\r
254 return COMPONENT_CLASS;
\r
256 return Collections.emptySet();
\r
259 private Object getSCLValue(String node) throws NodeManagerException {
\r
260 Object value = valueCache.get(node);
\r
261 if(value == null) {
\r
262 value = realm.getConnection().getVariableValue(node);
\r
263 valueCache.put(node, value);
\r
268 private void checkThreadAccess() throws NodeManagerException {
\r
269 if(Thread.currentThread() != realm.getThread())
\r
270 throw new NotInRealmException();
\r
274 public String getPropertyURI(String parent, String property) {
\r
275 return "http://www.simantics.org/Modeling-1.2/CommandSession/hasValue";
\r