]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling/src/org/simantics/modeling/scl/SCLNodeManager.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / scl / SCLNodeManager.java
1 package org.simantics.modeling.scl;\r
2 \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
8 \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
20 \r
21 import gnu.trove.map.hash.THashMap;\r
22 import gnu.trove.procedure.TObjectProcedure;\r
23 import gnu.trove.set.hash.THashSet;\r
24 \r
25 public class SCLNodeManager extends AbstractNodeManager<String> {\r
26 \r
27     public static final String ROOT = "@";\r
28     \r
29     SCLRealm realm;\r
30     THashMap<String, Object> valueCache = new THashMap<String, Object>(); \r
31     THashMap<String, THashSet<Runnable>> listeners = new THashMap<String, THashSet<Runnable>>(); \r
32     \r
33     AtomicBoolean fireNodeListenersScheduled = new AtomicBoolean(false);\r
34     Runnable fireNodeListeners = new Runnable() {\r
35         @Override\r
36         public void run() {\r
37             fireNodeListenersScheduled.set(false);\r
38             final TObjectProcedure<Runnable> procedure = new TObjectProcedure<Runnable>() {\r
39                 @Override\r
40                 public boolean execute(Runnable object) {\r
41                     object.run();\r
42                     return true;\r
43                 }\r
44             };\r
45             synchronized(listeners) {\r
46                 listeners.forEachValue(new TObjectProcedure<THashSet<Runnable>>() {\r
47                     @Override\r
48                     public boolean execute(THashSet<Runnable> object) {\r
49                         object.forEach(procedure);\r
50                         return true;\r
51                     }\r
52                 });\r
53             }\r
54         }\r
55     };\r
56     \r
57     Runnable clearValueCache = new Runnable() {\r
58         @Override\r
59         public void run() {\r
60             valueCache.clear(); \r
61         }\r
62     };\r
63     \r
64     public SCLNodeManager(SCLRealm realm) {\r
65         super();\r
66         this.realm = realm;\r
67     }\r
68 \r
69     @Override\r
70     public Realm getRealm() {\r
71         return realm;\r
72     }\r
73 \r
74     public String getRoot() {\r
75         return ROOT;\r
76     }\r
77     \r
78     @Override\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
85                 return name;\r
86         } else\r
87             return node;\r
88     }\r
89 \r
90     @Override\r
91     public void addNodeListener(String node, Runnable listener) {\r
92         synchronized(listeners) {\r
93             THashSet<Runnable> l = listeners.get(node);\r
94             if(l == null) {\r
95                 l = new THashSet<Runnable>();\r
96                 listeners.put(node, l);\r
97             }\r
98             l.add(listener);\r
99         }\r
100         realm.asyncExec(listener);\r
101     }\r
102 \r
103     @Override\r
104     public void removeNodeListener(String node, Runnable listener) {\r
105         synchronized(listeners) {\r
106             THashSet<Runnable> l = listeners.get(node);\r
107             if(l != null) {\r
108                 l.remove(listener);\r
109                 if(l.isEmpty())\r
110                     listeners.remove(node);\r
111             }\r
112         }\r
113     }\r
114     \r
115     public void fireNodeListeners() {\r
116         if(!fireNodeListenersScheduled.getAndSet(true))\r
117             realm.asyncExec(fireNodeListeners);\r
118     }\r
119     \r
120     public void fireNodeListenersSync() {\r
121         try {\r
122                         realm.syncExec(fireNodeListeners);\r
123                 } catch (InterruptedException e) {\r
124                         e.printStackTrace();\r
125                 }\r
126     }\r
127 \r
128     public void refreshVariables() {\r
129         realm.asyncExec(clearValueCache);\r
130         fireNodeListeners();\r
131     }\r
132 \r
133     public void refreshVariablesSync() {\r
134         try {\r
135                         realm.syncExec(clearValueCache);\r
136                 } catch (InterruptedException e) {\r
137                         e.printStackTrace();\r
138                 }\r
139         fireNodeListenersSync();\r
140     }\r
141 \r
142     @Override\r
143     public String getNode(String path) throws NodeManagerException {\r
144         checkThreadAccess();\r
145         throw new UnsupportedOperationException();\r
146     }\r
147 \r
148     @Override\r
149     public String getChild(String node, String name)\r
150             throws NodeManagerException {\r
151         checkThreadAccess();\r
152         return null;\r
153     }\r
154 \r
155     @Override\r
156     public String getProperty(String node, String name)\r
157             throws NodeManagerException {\r
158         checkThreadAccess();\r
159         if(node.equals(ROOT))\r
160             return name;\r
161         else\r
162             return null;\r
163     }\r
164 \r
165     @Override\r
166     public List<String> getChildren(String node) throws NodeManagerException {\r
167         checkThreadAccess();\r
168         return Collections.emptyList();\r
169     }\r
170 \r
171     @Override\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
176                 \r
177         Set<String> variables = realm.getConnection().getVariables();\r
178         return new ArrayList<String>(variables);\r
179                 \r
180     }\r
181 \r
182     @Override\r
183     public Datatype getDatatype(String node) throws NodeManagerException {\r
184         checkThreadAccess();\r
185         try {\r
186             Datatype type = getDatatypeForValue(getSCLValue(node));\r
187             return type;\r
188         } catch (DatabaseException e) {\r
189             e.printStackTrace();\r
190         }\r
191         return null;\r
192     }\r
193 \r
194     @Override\r
195     public Object getValue(String node, Binding binding) throws NodeManagerException {\r
196         checkThreadAccess();\r
197         return getSCLValue(node);\r
198     }\r
199 \r
200     \r
201     private Type getType(String name) {\r
202         return realm.getConnection().getVariableType(name);\r
203     }\r
204 \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
212         \r
213         if (value instanceof List) return null;\r
214         \r
215         if (value instanceof Object) return null;\r
216         \r
217         if (value == null) return null;\r
218         \r
219         else throw new DatabaseException("No Datatype for value " + value);\r
220     }\r
221 \r
222     @Override\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
230     }\r
231 \r
232     public void setValue(String node, Type type, Object value)\r
233             throws NodeManagerException {\r
234         \r
235         checkThreadAccess();\r
236         valueCache.put(node, value);\r
237         realm.getConnection().setVariable(node, type, value);\r
238         \r
239         NodeSupport support = SCLSessionManager.getOrCreateNodeSupport(realm.getId());\r
240         support.structureCache.put(ROOT, null);\r
241         support.valueCache.put(node, null);\r
242         \r
243         realm.nodeManager.valueCache.put(node, value);\r
244         realm.nodeManager.\r
245         refreshVariables();\r
246     }\r
247     \r
248     static final Set<String> COMPONENT_CLASS = Collections.singleton(StructuralResource2.URIs.Component);\r
249             \r
250     @Override\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
255         else\r
256             return Collections.emptySet();\r
257     }\r
258 \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
264         }\r
265         return value;\r
266     }\r
267     \r
268     private void checkThreadAccess() throws NodeManagerException {\r
269         if(Thread.currentThread() != realm.getThread())\r
270             throw new NotInRealmException();\r
271     }\r
272     \r
273     @Override\r
274     public String getPropertyURI(String parent, String property) {\r
275         return "http://www.simantics.org/Modeling-1.2/CommandSession/hasValue";\r
276     }\r
277 }\r