ea82e7e4ccdbcb97b27d456dc7f5da5df8ea0045
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / scl / SCLRealm.java
1 package org.simantics.modeling.scl;
2
3 import java.io.IOException;
4 import java.util.Map;
5 import java.util.concurrent.ExecutorService;
6 import java.util.concurrent.LinkedBlockingQueue;
7 import java.util.concurrent.Semaphore;
8 import java.util.concurrent.ThreadFactory;
9 import java.util.concurrent.ThreadPoolExecutor;
10 import java.util.concurrent.TimeUnit;
11
12 import org.simantics.databoard.Bindings;
13 import org.simantics.databoard.binding.Binding;
14 import org.simantics.databoard.binding.mutable.Variant;
15 import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;
16 import org.simantics.modeling.SCLTypeUtils;
17 import org.simantics.scl.compiler.commands.CommandSession;
18 import org.simantics.scl.compiler.types.Type;
19 import org.simantics.scl.runtime.SCLContext;
20 import org.simantics.scl.runtime.function.Function;
21 import org.simantics.scl.runtime.tuple.Tuple0;
22 import org.simantics.simulator.variable.NodeManager;
23 import org.simantics.simulator.variable.Realm;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import gnu.trove.map.hash.THashMap;
28
29 public class SCLRealm implements Realm {
30     private static final Logger LOGGER = LoggerFactory.getLogger(SCLRealm.class);
31
32     public static final String SCL = "scl";
33     
34     THashMap<String,Type> contextTypes = new THashMap<String,Type>();
35     
36     CommandSession connection;
37     String id;
38     Thread executorThread;
39     ExecutorService executor = new ThreadPoolExecutor(0, 1, 60, TimeUnit.SECONDS,
40             new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
41         @Override
42         public Thread newThread(Runnable r) {
43             executorThread = new Thread(r);
44             return executorThread;
45         }
46     });
47     
48     Semaphore beginSyncExec = new Semaphore(0);
49     Semaphore endSyncExec = new Semaphore(0);
50     
51     SCLNodeManager nodeManager;
52     
53     Runnable scheduleSyncExec = new Runnable() {
54         @Override
55         public void run() {
56             beginSyncExec.release();
57             try {
58                 endSyncExec.acquire();
59             } catch (InterruptedException e) {
60             }
61         }
62     };
63     
64     SCLRealm(CommandSession connection, String id) {
65         this.connection = connection;
66         this.id = id;
67         this.nodeManager = new SCLNodeManager(this);
68     }
69
70     public String getId() {
71         return id;
72     }
73     
74     public CommandSession getConnection() {
75         return connection;
76     }
77     
78     public Thread getThread() {
79         return executorThread;
80     }
81     
82     @SuppressWarnings({ "rawtypes", "unchecked" })
83     public Object syncExec(Function fun) throws InterruptedException {
84         executor.execute(scheduleSyncExec);
85         
86         SCLContext context = SCLContext.getCurrent();
87         CommandSession oldConnection = (CommandSession)context.put(SCL, connection);
88         
89         try {
90             beginSyncExec.acquire();
91             Thread oldThread = executorThread;
92             executorThread = Thread.currentThread();
93             try {
94                 return fun.apply(Tuple0.INSTANCE);
95             } finally {
96                 executorThread = oldThread;
97                 endSyncExec.release();
98             }
99         } finally {
100             context.put(SCL, oldConnection);
101         }
102     }
103     
104     @SuppressWarnings("rawtypes")
105     public void asyncExec(final Function fun) {
106         executor.execute(new Runnable() {
107             @SuppressWarnings("unchecked")
108             @Override
109             public void run() {
110                 SCLContext context = SCLContext.getCurrent();
111                 context.put(SCL, connection);
112                 fun.apply(Tuple0.INSTANCE);
113             }
114         });
115     }
116
117     @Override
118     public void syncExec(Runnable runnable) throws InterruptedException {
119         
120         if(executorThread == Thread.currentThread()) {
121             try {
122                 runnable.run();
123             } catch (Throwable t) {
124                 LOGGER.error("Runnable failed in syncExec.", t);
125             } finally {
126             }
127             return;
128         }
129
130         executor.execute(scheduleSyncExec);
131         
132         beginSyncExec.acquire();
133         Thread oldThread = executorThread;
134         executorThread = Thread.currentThread();
135         try {
136             runnable.run();
137         } catch (Throwable t) {
138             LOGGER.error("Runnable failed in syncExec.", t);
139         } finally {
140             executorThread = oldThread;
141             endSyncExec.release();
142         }
143     }
144
145     @Override
146     public void asyncExec(Runnable runnable) {
147
148         if(executorThread == Thread.currentThread()) {
149             try {
150                 runnable.run();
151             } catch (Throwable t) {
152                 LOGGER.error("Runnable failed in asyncExec.", t);
153             } finally {
154             }
155             return;
156         }
157         
158         executor.execute(runnable);
159     }
160     
161     public void refreshVariables() {
162         nodeManager.refreshVariables();
163     }
164     
165     public void refreshVariablesSync() {
166         nodeManager.refreshVariablesSync();
167     }
168
169     public void close() {
170         SCLSessionManager.CONNECTIONS.remove(id);
171         executor.shutdown();
172         try {
173             executor.awaitTermination(500L, TimeUnit.MILLISECONDS);
174         } catch (InterruptedException e) {
175         }
176         //connection.close();
177     }
178
179     public NodeManager<String> getNodeManager() {
180         return nodeManager;
181     }
182     
183     private SCLState getState() {
184         SCLState state = new SCLState();
185         for(String key : connection.getVariables()) {
186                 Object value = connection.getVariableValue(key);
187                 try {
188                         Binding b = Bindings.getBinding(value.getClass());
189                         state.values.put(key, new Variant(b, value));
190                 } catch (Exception e) {
191                 }
192         }
193         return state;
194     }
195     
196     public void applyState(byte[] blob) {
197         try {
198                         SCLState state = (SCLState)SCLState.BINDING.serializer().deserialize(blob);
199                 for(Map.Entry<String,Variant> entry : state.values.entrySet()) {
200                         String key = entry.getKey();
201                         Variant value = entry.getValue();
202                         Type type = SCLTypeUtils.getType(value.type());
203                         if (type.getClassId() != Type.VAR_ID) {
204                             // do not add the property if type cannot be inferred
205                             connection.setVariable(key, type, value.getValue());
206                         }
207                 }
208                 } catch (RuntimeSerializerConstructionException e) {
209                 } catch (IOException e) {
210                 }
211     }
212     
213     public byte[] serialize() {
214         SCLState state = getState();
215         try {
216                         return SCLState.BINDING.serializer().serialize(state);
217                 } catch (RuntimeSerializerConstructionException e) {
218                         return null;
219                 } catch (IOException e) {
220                         return null;
221                 }
222     }
223     
224 }