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.modeling.ModelingResources;
\r
15 import org.simantics.scl.compiler.types.Type;
\r
16 import org.simantics.simulator.variable.Realm;
\r
17 import org.simantics.simulator.variable.exceptions.NodeManagerException;
\r
18 import org.simantics.simulator.variable.exceptions.NotInRealmException;
\r
19 import org.simantics.simulator.variable.impl.AbstractNodeManager;
\r
20 import org.simantics.structural.stubs.StructuralResource2;
\r
22 import gnu.trove.map.hash.THashMap;
\r
23 import gnu.trove.procedure.TObjectProcedure;
\r
24 import gnu.trove.set.hash.THashSet;
\r
26 public class SCLNodeManager extends AbstractNodeManager<String> {
\r
28 public static final String ROOT = "@";
\r
31 THashMap<String, Object> valueCache = new THashMap<String, Object>();
\r
32 THashMap<String, THashSet<Runnable>> listeners = new THashMap<String, THashSet<Runnable>>();
\r
34 AtomicBoolean fireNodeListenersScheduled = new AtomicBoolean(false);
\r
35 Runnable fireNodeListeners = new Runnable() {
\r
38 fireNodeListenersScheduled.set(false);
\r
39 final TObjectProcedure<Runnable> procedure = new TObjectProcedure<Runnable>() {
\r
41 public boolean execute(Runnable object) {
\r
46 synchronized(listeners) {
\r
47 listeners.forEachValue(new TObjectProcedure<THashSet<Runnable>>() {
\r
49 public boolean execute(THashSet<Runnable> object) {
\r
50 object.forEach(procedure);
\r
58 Runnable clearValueCache = new Runnable() {
\r
61 valueCache.clear();
\r
65 public SCLNodeManager(SCLRealm realm) {
\r
71 public Realm getRealm() {
\r
75 public String getRoot() {
\r
80 public String getName(String node) {
\r
81 if(ROOT.equals(node)) {
\r
82 String id = realm.id;
\r
83 int lastSlash = id.lastIndexOf("/");
\r
84 if(lastSlash == -1) throw new IllegalStateException("Invalid realm id " + id);
\r
85 String name = id.substring(lastSlash+1);
\r
92 public void addNodeListener(String node, Runnable listener) {
\r
93 synchronized(listeners) {
\r
94 THashSet<Runnable> l = listeners.get(node);
\r
96 l = new THashSet<Runnable>();
\r
97 listeners.put(node, l);
\r
101 realm.asyncExec(listener);
\r
105 public void removeNodeListener(String node, Runnable listener) {
\r
106 synchronized(listeners) {
\r
107 THashSet<Runnable> l = listeners.get(node);
\r
109 l.remove(listener);
\r
111 listeners.remove(node);
\r
116 public void fireNodeListeners() {
\r
117 if(!fireNodeListenersScheduled.getAndSet(true))
\r
118 realm.asyncExec(fireNodeListeners);
\r
121 public void fireNodeListenersSync() {
\r
123 realm.syncExec(fireNodeListeners);
\r
124 } catch (InterruptedException e) {
\r
125 e.printStackTrace();
\r
129 public void refreshVariables() {
\r
130 realm.asyncExec(clearValueCache);
\r
131 fireNodeListeners();
\r
134 public void refreshVariablesSync() {
\r
136 realm.syncExec(clearValueCache);
\r
137 } catch (InterruptedException e) {
\r
138 e.printStackTrace();
\r
140 fireNodeListenersSync();
\r
144 public String getNode(String path) throws NodeManagerException {
\r
145 checkThreadAccess();
\r
146 throw new UnsupportedOperationException();
\r
150 public String getChild(String node, String name)
\r
151 throws NodeManagerException {
\r
152 checkThreadAccess();
\r
157 public String getProperty(String node, String name)
\r
158 throws NodeManagerException {
\r
159 checkThreadAccess();
\r
160 if(node.equals(ROOT))
\r
167 public List<String> getChildren(String node) throws NodeManagerException {
\r
168 checkThreadAccess();
\r
169 return Collections.emptyList();
\r
173 public List<String> getProperties(String node) throws NodeManagerException {
\r
174 checkThreadAccess();
\r
175 if(!node.equals(ROOT))
\r
176 return Collections.emptyList();
\r
178 Set<String> variables = realm.getConnection().getVariables();
\r
179 return new ArrayList<String>(variables);
\r
184 public Datatype getDatatype(String node) throws NodeManagerException {
\r
185 checkThreadAccess();
\r
187 Datatype type = getDatatypeForValue(getSCLValue(node));
\r
189 } catch (DatabaseException e) {
\r
190 e.printStackTrace();
\r
196 public Object getValue(String node, Binding binding) throws NodeManagerException {
\r
197 checkThreadAccess();
\r
198 return getSCLValue(node);
\r
202 private Type getType(String name) {
\r
203 return realm.getConnection().getVariableType(name);
\r
206 private Datatype getDatatypeForValue(Object value) throws DatabaseException {
\r
207 if(value instanceof Double) return Datatypes.DOUBLE;
\r
208 if(value instanceof Float) return Datatypes.FLOAT;
\r
209 if(value instanceof Integer) return Datatypes.INTEGER;
\r
210 if(value instanceof Long) return Datatypes.LONG;
\r
211 if(value instanceof String) return Datatypes.STRING;
\r
212 if(value instanceof Boolean) return Datatypes.BOOLEAN;
\r
214 if (value instanceof List) return null;
\r
216 if (value instanceof Object) return null;
\r
218 if (value == null) return null;
\r
220 else throw new DatabaseException("No Datatype for value " + value);
\r
224 public void setValue(String node, Object value, Binding binding)
\r
225 throws NodeManagerException {
\r
226 checkThreadAccess();
\r
227 valueCache.put(node, value);
\r
228 realm.getConnection().setVariable(node, getType(node), value);
\r
229 realm.nodeManager.valueCache.put(node, value);
\r
230 refreshVariables();
\r
233 public void setValue(String node, Type type, Object value)
\r
234 throws NodeManagerException {
\r
236 checkThreadAccess();
\r
237 valueCache.put(node, value);
\r
238 realm.getConnection().setVariable(node, type, value);
\r
240 NodeSupport support = SCLSessionManager.getOrCreateNodeSupport(realm.getId());
\r
241 support.structureCache.put(ROOT, null);
\r
242 support.valueCache.put(node, null);
\r
244 realm.nodeManager.valueCache.put(node, value);
\r
246 refreshVariables();
\r
249 static final Set<String> COMPONENT_CLASS = Collections.singleton(StructuralResource2.URIs.Component);
\r
252 public Set<String> getClassifications(String node) throws NodeManagerException {
\r
253 checkThreadAccess();
\r
254 if(node.equals(ROOT))
\r
255 return COMPONENT_CLASS;
\r
257 return Collections.emptySet();
\r
260 private Object getSCLValue(String node) throws NodeManagerException {
\r
261 Object value = valueCache.get(node);
\r
262 if(value == null) {
\r
263 value = realm.getConnection().getVariableValue(node);
\r
264 valueCache.put(node, value);
\r
269 private void checkThreadAccess() throws NodeManagerException {
\r
270 if(Thread.currentThread() != realm.getThread())
\r
271 throw new NotInRealmException();
\r
275 public String getPropertyURI(String parent, String property) {
\r
276 return ModelingResources.URIs.SCLCommandSession_hasValue;
\r