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