--- /dev/null
+package org.simantics.modeling.scl;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import java.io.IOException;\r
+import java.util.Map;\r
+import java.util.concurrent.ExecutorService;\r
+import java.util.concurrent.LinkedBlockingQueue;\r
+import java.util.concurrent.Semaphore;\r
+import java.util.concurrent.ThreadFactory;\r
+import java.util.concurrent.ThreadPoolExecutor;\r
+import java.util.concurrent.TimeUnit;\r
+\r
+import org.simantics.Logger;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
+import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;\r
+import org.simantics.modeling.SCLTypeUtils;\r
+import org.simantics.scl.compiler.commands.CommandSession;\r
+import org.simantics.scl.compiler.types.Type;\r
+import org.simantics.scl.runtime.SCLContext;\r
+import org.simantics.scl.runtime.function.Function;\r
+import org.simantics.scl.runtime.tuple.Tuple0;\r
+import org.simantics.simulator.variable.NodeManager;\r
+import org.simantics.simulator.variable.Realm;\r
+\r
+public class SCLRealm implements Realm {\r
+ public static final String SCL = "scl";\r
+ \r
+ THashMap<String,Type> contextTypes = new THashMap<String,Type>();\r
+ \r
+ CommandSession connection;\r
+ String id;\r
+ Thread executorThread;\r
+ ExecutorService executor = new ThreadPoolExecutor(0, 1, 60, TimeUnit.SECONDS,\r
+ new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {\r
+ @Override\r
+ public Thread newThread(Runnable r) {\r
+ executorThread = new Thread(r);\r
+ return executorThread;\r
+ }\r
+ });\r
+ \r
+ Semaphore beginSyncExec = new Semaphore(0);\r
+ Semaphore endSyncExec = new Semaphore(0);\r
+ \r
+ SCLNodeManager nodeManager;\r
+ \r
+ Runnable scheduleSyncExec = new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ beginSyncExec.release();\r
+ try {\r
+ endSyncExec.acquire();\r
+ } catch (InterruptedException e) {\r
+ }\r
+ }\r
+ };\r
+ \r
+ SCLRealm(CommandSession connection, String id) {\r
+ this.connection = connection;\r
+ this.id = id;\r
+ this.nodeManager = new SCLNodeManager(this);\r
+ }\r
+\r
+ public String getId() {\r
+ return id;\r
+ }\r
+ \r
+ public CommandSession getConnection() {\r
+ return connection;\r
+ }\r
+ \r
+ public Thread getThread() {\r
+ return executorThread;\r
+ }\r
+ \r
+ @SuppressWarnings({ "rawtypes", "unchecked" })\r
+ public Object syncExec(Function fun) throws InterruptedException {\r
+ executor.execute(scheduleSyncExec);\r
+ \r
+ SCLContext context = SCLContext.getCurrent();\r
+ CommandSession oldConnection = (CommandSession)context.put(SCL, connection);\r
+ \r
+ try {\r
+ beginSyncExec.acquire();\r
+ Thread oldThread = executorThread;\r
+ executorThread = Thread.currentThread();\r
+ try {\r
+ return fun.apply(Tuple0.INSTANCE);\r
+ } finally {\r
+ executorThread = oldThread;\r
+ endSyncExec.release();\r
+ }\r
+ } finally {\r
+ context.put(SCL, oldConnection);\r
+ }\r
+ }\r
+ \r
+ @SuppressWarnings("rawtypes")\r
+ public void asyncExec(final Function fun) {\r
+ executor.execute(new Runnable() {\r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public void run() {\r
+ SCLContext context = SCLContext.getCurrent();\r
+ context.put(SCL, connection);\r
+ fun.apply(Tuple0.INSTANCE);\r
+ }\r
+ });\r
+ }\r
+\r
+ @Override\r
+ public void syncExec(Runnable runnable) throws InterruptedException {\r
+ \r
+ if(executorThread == Thread.currentThread()) {\r
+ try {\r
+ runnable.run();\r
+ } catch (Throwable t) {\r
+ Logger.defaultLogError(t);\r
+ } finally {\r
+ }\r
+ return;\r
+ }\r
+\r
+ executor.execute(scheduleSyncExec);\r
+ \r
+ beginSyncExec.acquire();\r
+ Thread oldThread = executorThread;\r
+ executorThread = Thread.currentThread();\r
+ try {\r
+ runnable.run();\r
+ } catch (Throwable t) {\r
+ Logger.defaultLogError(t);\r
+ } finally {\r
+ executorThread = oldThread;\r
+ endSyncExec.release();\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void asyncExec(Runnable runnable) {\r
+\r
+ if(executorThread == Thread.currentThread()) {\r
+ try {\r
+ runnable.run();\r
+ } catch (Throwable t) {\r
+ Logger.defaultLogError(t);\r
+ } finally {\r
+ }\r
+ return;\r
+ }\r
+ \r
+ executor.execute(runnable);\r
+ }\r
+ \r
+ public void refreshVariables() {\r
+ nodeManager.refreshVariables();\r
+ }\r
+ \r
+ public void refreshVariablesSync() {\r
+ nodeManager.refreshVariablesSync();\r
+ }\r
+\r
+ public void close() {\r
+ SCLSessionManager.CONNECTIONS.remove(id);\r
+ executor.shutdown();\r
+ try {\r
+ executor.awaitTermination(500L, TimeUnit.MILLISECONDS);\r
+ } catch (InterruptedException e) {\r
+ }\r
+ //connection.close();\r
+ }\r
+\r
+ public NodeManager<String> getNodeManager() {\r
+ return nodeManager;\r
+ }\r
+ \r
+ private SCLState getState() {\r
+ SCLState state = new SCLState();\r
+ for(String key : connection.getVariables()) {\r
+ Object value = connection.getVariableValue(key);\r
+ try {\r
+ Binding b = Bindings.getBinding(value.getClass());\r
+ state.values.put(key, new Variant(b, value));\r
+ } catch (Exception e) {\r
+ }\r
+ }\r
+ return state;\r
+ }\r
+ \r
+ public void applyState(byte[] blob) {\r
+ try {\r
+ SCLState state = (SCLState)SCLState.BINDING.serializer().deserialize(blob);\r
+ for(Map.Entry<String,Variant> entry : state.values.entrySet()) {\r
+ String key = entry.getKey();\r
+ Variant value = entry.getValue();\r
+ Type type = SCLTypeUtils.getType(value.type());\r
+ if (type.getClassId() != Type.VAR_ID) {\r
+ // do not add the property if type cannot be inferred\r
+ connection.setVariable(key, type, value.getValue());\r
+ }\r
+ }\r
+ } catch (RuntimeSerializerConstructionException e) {\r
+ } catch (IOException e) {\r
+ }\r
+ }\r
+ \r
+ public byte[] serialize() {\r
+ SCLState state = getState();\r
+ try {\r
+ return SCLState.BINDING.serializer().serialize(state);\r
+ } catch (RuntimeSerializerConstructionException e) {\r
+ return null;\r
+ } catch (IOException e) {\r
+ return null;\r
+ }\r
+ }\r
+ \r
+}\r