From 14a4f7a9d486fba5be815e511fb2a497fca4eb70 Mon Sep 17 00:00:00 2001 From: Antti Villberg Date: Tue, 27 Feb 2018 11:00:13 +0200 Subject: [PATCH] Simulator toolkit enhancements The basic simulator node manager and its supporting structures have been moved to org.simantics.simulator[.toolkit] and stripped of any dependency the Simantics database interfaces. org.simantics.simulator.toolkit.db now contains the parts that bind the simulator toolkit interfaces to the Simantics DB. refs #7782 Change-Id: I266faaec323c772767d7a32331ed27e9f893f473 --- .../simantics/db/layer0/StandardEngine.java | 15 - .../org/simantics/db/layer0/StandardNode.java | 5 - .../simulation/data/AbstractDatasource.java | 18 +- .../simulation/data/DatasourceAdapter.java | 2 +- .../simulation/data/PseudoSolver.java | 6 + .../simulation/data/VariableHandle.java | 6 + .../experiment/ExperimentState.java | 2 +- .../.classpath | 7 + .../.project | 28 ++ .../META-INF/MANIFEST.MF | 10 + .../build.properties | 4 + .../db/ExperimentStateExternalRead.java | 42 +++ .../toolkit/db}/StandardSessionManager.java | 43 +-- .../.classpath | 7 + .../org.simantics.simulator.toolkit/.project | 28 ++ .../META-INF/MANIFEST.MF | 15 + .../build.properties | 4 + .../DynamicExperimentActionContext.java | 29 ++ .../toolkit/DynamicExperimentThread.java | 298 +++++++++++++++ .../DynamicExperimentThreadListener.java | 13 + ...DynamicExperimentThreadSequenceRunner.java | 72 ++++ .../toolkit/StandardExperimentStates.java | 124 +++++++ .../simulator/toolkit/StandardNode.java | 14 + .../toolkit}/StandardNodeManager.java | 347 +++++++++--------- .../toolkit/StandardNodeManagerSupport.java | 30 ++ .../simulator/toolkit}/StandardRealm.java | 66 ++-- bundles/org.simantics.simulator/.classpath | 7 + bundles/org.simantics.simulator/.project | 28 ++ .../META-INF/MANIFEST.MF | 10 + .../org.simantics.simulator/build.properties | 4 + .../simantics/simulator/ExperimentState.java | 25 ++ .../simulator/IDynamicExperimentLocal.java | 36 ++ .../simantics/simulator/IExperimentLocal.java | 35 ++ .../META-INF/MANIFEST.MF | 4 +- .../simantics/spreadsheet/graph/GraphUI.java | 2 +- .../spreadsheet/graph/SpreadsheetBook.java | 21 +- .../spreadsheet/graph/SpreadsheetEngine.java | 1 + .../graph/SpreadsheetGraphUtils.java | 2 +- .../graph/SpreadsheetNodeManager.java | 30 +- .../spreadsheet/graph/SpreadsheetRealm.java | 7 +- .../graph/SpreadsheetSessionManager.java | 4 +- .../spreadsheet/graph/function/All.java | 2 +- bundles/pom.xml | 3 + .../org.simantics.sdk.feature/feature.xml | 8 + .../.project | 17 + .../build.properties | 1 + .../feature.xml | 31 ++ .../.project | 17 + .../build.properties | 1 + .../feature.xml | 62 ++++ .../feature.xml | 4 + features/pom.xml | 2 + 52 files changed, 1316 insertions(+), 283 deletions(-) delete mode 100644 bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardEngine.java delete mode 100644 bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardNode.java create mode 100644 bundles/org.simantics.simulator.toolkit.db/.classpath create mode 100644 bundles/org.simantics.simulator.toolkit.db/.project create mode 100644 bundles/org.simantics.simulator.toolkit.db/META-INF/MANIFEST.MF create mode 100644 bundles/org.simantics.simulator.toolkit.db/build.properties create mode 100644 bundles/org.simantics.simulator.toolkit.db/src/org/simantics/simulator/toolkit/db/ExperimentStateExternalRead.java rename bundles/{org.simantics.db.layer0/src/org/simantics/db/layer0 => org.simantics.simulator.toolkit.db/src/org/simantics/simulator/toolkit/db}/StandardSessionManager.java (85%) create mode 100644 bundles/org.simantics.simulator.toolkit/.classpath create mode 100644 bundles/org.simantics.simulator.toolkit/.project create mode 100644 bundles/org.simantics.simulator.toolkit/META-INF/MANIFEST.MF create mode 100644 bundles/org.simantics.simulator.toolkit/build.properties create mode 100644 bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentActionContext.java create mode 100644 bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThread.java create mode 100644 bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThreadListener.java create mode 100644 bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThreadSequenceRunner.java create mode 100644 bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardExperimentStates.java create mode 100644 bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardNode.java rename bundles/{org.simantics.db.layer0/src/org/simantics/db/layer0 => org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit}/StandardNodeManager.java (52%) create mode 100644 bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardNodeManagerSupport.java rename bundles/{org.simantics.db.layer0/src/org/simantics/db/layer0 => org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit}/StandardRealm.java (87%) create mode 100644 bundles/org.simantics.simulator/.classpath create mode 100644 bundles/org.simantics.simulator/.project create mode 100644 bundles/org.simantics.simulator/META-INF/MANIFEST.MF create mode 100644 bundles/org.simantics.simulator/build.properties create mode 100644 bundles/org.simantics.simulator/src/org/simantics/simulator/ExperimentState.java create mode 100644 bundles/org.simantics.simulator/src/org/simantics/simulator/IDynamicExperimentLocal.java create mode 100644 bundles/org.simantics.simulator/src/org/simantics/simulator/IExperimentLocal.java create mode 100644 features/org.simantics.simulator.toolkit.db.feature/.project create mode 100644 features/org.simantics.simulator.toolkit.db.feature/build.properties create mode 100644 features/org.simantics.simulator.toolkit.db.feature/feature.xml create mode 100644 features/org.simantics.simulator.toolkit.feature/.project create mode 100644 features/org.simantics.simulator.toolkit.feature/build.properties create mode 100644 features/org.simantics.simulator.toolkit.feature/feature.xml diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardEngine.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardEngine.java deleted file mode 100644 index 31e73877d..000000000 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardEngine.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.simantics.db.layer0; - -import java.util.Map; - -import org.simantics.simulator.variable.exceptions.NodeManagerException; - -public interface StandardEngine { - - Object getValue(Node node) throws NodeManagerException; - void setValue(Node node, Object value) throws NodeManagerException; - String getName(Node node); - Map getChildren(Node node); - Map getProperties(Node node); - -} diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardNode.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardNode.java deleted file mode 100644 index c29dc8f65..000000000 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardNode.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.simantics.db.layer0; - -public interface StandardNode { - -} diff --git a/bundles/org.simantics.simulation/src/org/simantics/simulation/data/AbstractDatasource.java b/bundles/org.simantics.simulation/src/org/simantics/simulation/data/AbstractDatasource.java index 4a15cba52..7b6e791da 100644 --- a/bundles/org.simantics.simulation/src/org/simantics/simulation/data/AbstractDatasource.java +++ b/bundles/org.simantics.simulation/src/org/simantics/simulation/data/AbstractDatasource.java @@ -20,7 +20,7 @@ import org.simantics.utils.datastructures.ListenerList; */ public abstract class AbstractDatasource implements Datasource { - protected ListenerList listeners = new ListenerList(DatasourceListener.class); + protected ListenerList listeners = new ListenerList<>(DatasourceListener.class); protected Lock readLock, writeLock; public AbstractDatasource() { @@ -40,20 +40,20 @@ public abstract class AbstractDatasource implements Datasource { listeners.remove(listener); } - protected void notifyStep() { - for (final DatasourceListener l : listeners.getListeners()) { + protected void notifyStep(Datasource source) { + for (DatasourceListener l : listeners.getListeners()) { if (l.getExecutor() == null) { - l.onStep( AbstractDatasource.this ); + l.onStep( source ); } else { - l.getExecutor().execute(new Runnable() { - public void run() { - l.onStep(AbstractDatasource.this); - } - }); + l.getExecutor().execute(() -> l.onStep(source)); } } } + protected void notifyStep() { + notifyStep(AbstractDatasource.this); + } + @Override public Lock readLock() { return readLock; diff --git a/bundles/org.simantics.simulation/src/org/simantics/simulation/data/DatasourceAdapter.java b/bundles/org.simantics.simulation/src/org/simantics/simulation/data/DatasourceAdapter.java index 1b6f9b6f8..1ee543f4c 100644 --- a/bundles/org.simantics.simulation/src/org/simantics/simulation/data/DatasourceAdapter.java +++ b/bundles/org.simantics.simulation/src/org/simantics/simulation/data/DatasourceAdapter.java @@ -169,7 +169,7 @@ public class DatasourceAdapter implements DatasourceListener { Object value = null; if (handle != null) { try { - value = handle.getValue(); + value = handle.getValue(source); } catch (AccessorException e) { if (failedIds.add(key)) logger.log(Level.SEVERE, e.toString(), e); diff --git a/bundles/org.simantics.simulation/src/org/simantics/simulation/data/PseudoSolver.java b/bundles/org.simantics.simulation/src/org/simantics/simulation/data/PseudoSolver.java index 9a5be411b..fd3e08a2b 100644 --- a/bundles/org.simantics.simulation/src/org/simantics/simulation/data/PseudoSolver.java +++ b/bundles/org.simantics.simulation/src/org/simantics/simulation/data/PseudoSolver.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Random; import org.simantics.databoard.Datatypes; +import org.simantics.databoard.accessor.error.AccessorException; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.NumberBinding; import org.simantics.databoard.binding.error.BindingException; @@ -160,6 +161,11 @@ public class PseudoSolver extends AbstractDatasource { public Object getValue() { return PseudoSolver.this.getValue(key, b); } + + @Override + public Object getValue(Datasource datasource) throws AccessorException { + return PseudoSolver.this.getValue(key, b); + } @Override public void dispose() { diff --git a/bundles/org.simantics.simulation/src/org/simantics/simulation/data/VariableHandle.java b/bundles/org.simantics.simulation/src/org/simantics/simulation/data/VariableHandle.java index d501dbecd..360ea96fc 100644 --- a/bundles/org.simantics.simulation/src/org/simantics/simulation/data/VariableHandle.java +++ b/bundles/org.simantics.simulation/src/org/simantics/simulation/data/VariableHandle.java @@ -36,6 +36,12 @@ public interface VariableHandle { */ Object getValue() throws AccessorException; + /** + * @return current value associated with this handle within the given Datasource + * @throws AccessorException if value cannot be retrieved + */ + Object getValue(Datasource datasource) throws AccessorException; + /** * Frees any resource related to this handle. */ diff --git a/bundles/org.simantics.simulation/src/org/simantics/simulation/experiment/ExperimentState.java b/bundles/org.simantics.simulation/src/org/simantics/simulation/experiment/ExperimentState.java index 66ec2d3cb..d724e8804 100644 --- a/bundles/org.simantics.simulation/src/org/simantics/simulation/experiment/ExperimentState.java +++ b/bundles/org.simantics.simulation/src/org/simantics/simulation/experiment/ExperimentState.java @@ -12,5 +12,5 @@ package org.simantics.simulation.experiment; public enum ExperimentState { - INITIALIZING, RUNNING, STOPPED, DISPOSED + INITIALIZING, RUNNING, STOPPED, TO_BE_DISPOSED, DISPOSED } diff --git a/bundles/org.simantics.simulator.toolkit.db/.classpath b/bundles/org.simantics.simulator.toolkit.db/.classpath new file mode 100644 index 000000000..b862a296d --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit.db/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.simantics.simulator.toolkit.db/.project b/bundles/org.simantics.simulator.toolkit.db/.project new file mode 100644 index 000000000..6684705c5 --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit.db/.project @@ -0,0 +1,28 @@ + + + org.simantics.simulator.toolkit.db + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/bundles/org.simantics.simulator.toolkit.db/META-INF/MANIFEST.MF b/bundles/org.simantics.simulator.toolkit.db/META-INF/MANIFEST.MF new file mode 100644 index 000000000..ea7f97e6d --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit.db/META-INF/MANIFEST.MF @@ -0,0 +1,10 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Simulator Toolkit for DB +Bundle-SymbolicName: org.simantics.simulator.toolkit.db +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.simantics.simulator.toolkit;bundle-version="1.0.0";visibility:=reexport, + org.simantics.db.layer0;bundle-version="1.1.0" +Export-Package: org.simantics.simulator.toolkit.db +Bundle-Vendor: Semantum Oy diff --git a/bundles/org.simantics.simulator.toolkit.db/build.properties b/bundles/org.simantics.simulator.toolkit.db/build.properties new file mode 100644 index 000000000..41eb6ade2 --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit.db/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/bundles/org.simantics.simulator.toolkit.db/src/org/simantics/simulator/toolkit/db/ExperimentStateExternalRead.java b/bundles/org.simantics.simulator.toolkit.db/src/org/simantics/simulator/toolkit/db/ExperimentStateExternalRead.java new file mode 100644 index 000000000..ad2b2c4c8 --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit.db/src/org/simantics/simulator/toolkit/db/ExperimentStateExternalRead.java @@ -0,0 +1,42 @@ +package org.simantics.simulator.toolkit.db; + +import org.simantics.db.ReadGraph; +import org.simantics.db.common.request.ParametrizedPrimitiveRead; +import org.simantics.db.exception.RuntimeDatabaseException; +import org.simantics.db.procedure.Listener; + +/** + * @author Antti Villberg + * @since 1.34.0 + */ +public class ExperimentStateExternalRead extends ParametrizedPrimitiveRead { + + private int value = 0; + private Listener listener = null; + + public ExperimentStateExternalRead(Object experiment) { + super(experiment); + } + + @Override + public void register(ReadGraph graph, Listener procedure) { + procedure.execute(value); + if (procedure.isDisposed()) + return; + if (listener != null) + throw new RuntimeDatabaseException("Internal error"); + listener = procedure; + } + + @Override + public void unregistered() { + listener = null; + } + + public void fire() { + value++; + if (listener != null) + listener.execute(value); + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardSessionManager.java b/bundles/org.simantics.simulator.toolkit.db/src/org/simantics/simulator/toolkit/db/StandardSessionManager.java similarity index 85% rename from bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardSessionManager.java rename to bundles/org.simantics.simulator.toolkit.db/src/org/simantics/simulator/toolkit/db/StandardSessionManager.java index cdd8e074c..62389597a 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardSessionManager.java +++ b/bundles/org.simantics.simulator.toolkit.db/src/org/simantics/simulator/toolkit/db/StandardSessionManager.java @@ -1,4 +1,4 @@ -package org.simantics.db.layer0; +package org.simantics.simulator.toolkit.db; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; @@ -9,12 +9,14 @@ import org.simantics.db.common.request.ParametrizedPrimitiveRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.variable.NodeSupport; import org.simantics.db.procedure.Listener; +import org.simantics.simulator.toolkit.StandardNodeManagerSupport; +import org.simantics.simulator.toolkit.StandardRealm; -abstract public class StandardSessionManager> { +public abstract class StandardSessionManager> { private ConcurrentHashMap>> realmListeners = new ConcurrentHashMap<>(); - private ConcurrentHashMap> REALMS = new ConcurrentHashMap>(); - private ConcurrentHashMap> SUPPORTS = new ConcurrentHashMap>(); + private ConcurrentHashMap> REALMS = new ConcurrentHashMap<>(); + private ConcurrentHashMap> SUPPORTS = new ConcurrentHashMap<>(); // Accessing Realms should be done over ParametrizedPrimitveRead for the // case if a realm is destroyed and new one is created with the same id than @@ -28,7 +30,6 @@ abstract public class StandardSessionManager> procedure) { - StandardRealm realm = REALMS.get(parameter); if (realm == null) { try { @@ -37,12 +38,12 @@ abstract public class StandardSessionManager> existing = getOrDisposeListener(parameter); assert(existing == null); realmListeners.put(parameter, procedure); @@ -56,10 +57,10 @@ abstract public class StandardSessionManager> getOrDisposeListener(String key) { Listener> listener = realmListeners.get(key); if(listener != null) { @@ -71,7 +72,7 @@ abstract public class StandardSessionManager realm) { if(realm != null) { REALMS.put(key, realm); @@ -88,25 +89,25 @@ abstract public class StandardSessionManager getOrCreateNodeSupport(ReadGraph graph, String id) throws DatabaseException { synchronized(SUPPORTS) { - NodeSupport result = SUPPORTS.get(id); - if(result == null) { - StandardRealm realm = getOrCreateRealm(graph, id); - result = new NodeSupport(realm.getNodeManager()); - SUPPORTS.put(id, result); - } - return result; + NodeSupport result = SUPPORTS.get(id); + if(result == null) { + StandardRealm realm = getOrCreateRealm(graph, id); + result = new NodeSupport(realm.getNodeManager()); + SUPPORTS.put(id, result); + } + return result; } } - + public StandardRealm getOrCreateRealm(ReadGraph graph, String id) throws DatabaseException { synchronized(REALMS) { return graph.syncRequest(new RealmRequest(id)); } } - + protected abstract Engine createEngine(ReadGraph graph, String id) throws DatabaseException; protected abstract StandardRealm createRealm(Engine engine, String id); - + public void removeRealm(WriteGraph graph, String id) throws DatabaseException { modifyRealms(id, null); // remove listeners from this realm @@ -116,7 +117,7 @@ abstract public class StandardSessionManager getRealms() { return REALMS.keySet(); } diff --git a/bundles/org.simantics.simulator.toolkit/.classpath b/bundles/org.simantics.simulator.toolkit/.classpath new file mode 100644 index 000000000..b862a296d --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.simantics.simulator.toolkit/.project b/bundles/org.simantics.simulator.toolkit/.project new file mode 100644 index 000000000..f04117506 --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit/.project @@ -0,0 +1,28 @@ + + + org.simantics.simulator.toolkit + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/bundles/org.simantics.simulator.toolkit/META-INF/MANIFEST.MF b/bundles/org.simantics.simulator.toolkit/META-INF/MANIFEST.MF new file mode 100644 index 000000000..99f251c47 --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit/META-INF/MANIFEST.MF @@ -0,0 +1,15 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Local Simulator Toolkit +Bundle-SymbolicName: org.simantics.simulator.toolkit +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.simantics.simulator.variable;bundle-version="1.0.0";visibility:=reexport, + org.simantics.simulator;bundle-version="1.0.0";visibility:=reexport, + gnu.trove3;bundle-version="3.0.3", + org.slf4j.api;bundle-version="1.7.25", + org.simantics.simulation.sequences;bundle-version="1.0.0", + org.eclipse.core.runtime, + org.simantics.databoard;bundle-version="0.6.6", + org.simantics.scl.osgi;bundle-version="1.0.4" +Export-Package: org.simantics.simulator.toolkit diff --git a/bundles/org.simantics.simulator.toolkit/build.properties b/bundles/org.simantics.simulator.toolkit/build.properties new file mode 100644 index 000000000..41eb6ade2 --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentActionContext.java b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentActionContext.java new file mode 100644 index 000000000..cdf478f3a --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentActionContext.java @@ -0,0 +1,29 @@ +package org.simantics.simulator.toolkit; + +import org.simantics.databoard.binding.Binding; +import org.simantics.simulation.sequences.action.AbstractActionContext; +import org.simantics.simulator.IDynamicExperimentLocal; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DynamicExperimentActionContext extends AbstractActionContext { + + private static final Logger LOGGER = LoggerFactory.getLogger(DynamicExperimentActionContext.class); + + final private IDynamicExperimentLocal experiment; + + public DynamicExperimentActionContext(IDynamicExperimentLocal experiment) { + this.experiment = experiment; + } + + @Override + public Object get(String variableName, Binding binding) { + return experiment.getVariableValueById(variableName); + } + + @Override + public void set(String variableName, Object value, Binding binding) { + experiment.setVariableValueById(variableName, value, binding); + } + +} diff --git a/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThread.java b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThread.java new file mode 100644 index 000000000..66cec38a4 --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThread.java @@ -0,0 +1,298 @@ +package org.simantics.simulator.toolkit; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.concurrent.Callable; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Semaphore; + +import org.simantics.simulator.ExperimentState; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Antti Villberg + * @since 1.34.0 + */ +abstract public class DynamicExperimentThread extends Thread { + + private static final Logger LOGGER = LoggerFactory.getLogger(DynamicExperimentThread.class); + + private CopyOnWriteArrayList listeners = new CopyOnWriteArrayList<>(); + + private ExperimentState state = StandardExperimentStates.CREATED; + + private long runStart = 0; + + private double desiredRealtimeRatio = 1000.0; + private double obtainedRealtimeRatio = 1.0; + + private long runTimeNs = 0; + private long endTimeNs = 0; + protected long simulationStepNs = 0; + protected double stepInSeconds = 1.0; + + public DynamicExperimentThread() { + } + + private void updateTimes() { + long time = System.nanoTime(); + long elapsed = time-runStart; + + obtainedRealtimeRatio = longToDoubleDivision(runTimeNs, elapsed); + } + + private long rt; + private long rt_l; + + protected double longToDoubleDivision(long l1, long l2) { + rt = l1 / l2; + rt_l = l1 % l2; + double d = ((double)rt_l)/((double)l2); + d += (double)rt; + return d; + } + + protected ArrayList tasks = new ArrayList<>(); + + abstract public void step(double stepLengthNanoSeconds); + + public boolean inState(Class state) { + return state.isInstance(this.state); + } + + public void initialize() throws Exception { + } + + public void deinitialize() throws Exception { + } + + long stepTime = 0; + long taskTime = 0; + + @Override + public void run() { + + try { + + try { + + initialize(); + + try { + runReally(); + } catch (Exception e) { + LOGGER.error("Unhandled exception while running simulation thread", e); + } + + } catch (Exception e) { + LOGGER.error("Unhandled exception while initializing simulation thread", e); + } + + } finally { + + try { + deinitialize(); + } catch (Exception e) { + LOGGER.error("Error while deinitializing simulation thread", e); + } + + } + + } + + protected boolean inActiveState() { + return !( + inState(StandardExperimentStates.Disposed.class) + || inState(StandardExperimentStates.Disposing.class) + //|| inState(StandardExperimentStates.Failure.class) + || inState(StandardExperimentStates.ToBeDisposed.class) + ); + } + + private void runReally() { + + while(inActiveState()) { + + if(inState(StandardExperimentStates.Running.class)) { + + long asd = System.nanoTime(); + step(simulationStepNs); + stepTime += System.nanoTime() - asd; + runTimeNs += simulationStepNs; + updateTimes(); + long asd2 = System.nanoTime(); + runTasks(); + taskTime += System.nanoTime() - asd2; + + System.err.println(" st = " + 1e-9*stepTime + " tt = " + 1e-9*taskTime); + + while(obtainedRealtimeRatio > desiredRealtimeRatio) { + int ran = runTasks(); + if(ran == 0) { + long elapsed = System.nanoTime()-runStart; + long deltaNs = BigDecimal.valueOf(runTimeNs).divide(BigDecimal.valueOf(desiredRealtimeRatio)).longValue() - elapsed; + + long deltaMs = deltaNs / 1000000; + int deltaNsRem = (int)(deltaNs % 1000000); + + if(deltaNs > 0) { + synchronized(tasks) { + try { + tasks.wait(deltaMs, deltaNsRem); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + updateTimes(); + } + + } else { + + while(!inState(StandardExperimentStates.Running.class) && inActiveState()) { + + synchronized(tasks) { + int ran = runTasks(); + if(ran == 0) { + try { + tasks.wait(Integer.MAX_VALUE); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + } + + } + + if(runTimeNs >= endTimeNs && inActiveState()) + changeState(StandardExperimentStates.STOPPED); + + } + + } + + Thread executorThread = this; + + Semaphore beginSyncExec = new Semaphore(0); + Semaphore endSyncExec = new Semaphore(0); + + Runnable scheduleSyncExec = () -> { + beginSyncExec.release(); + try { + endSyncExec.acquire(); + } catch (InterruptedException e) { + } + }; + + public int runTasks() { + ArrayList todo = new ArrayList<>(); + synchronized(tasks) { + todo.addAll(tasks); + tasks.clear(); + } + todo.forEach(Runnable::run); + return todo.size(); + } + + public void queue(Runnable runnable) { + synchronized(tasks) { + tasks.add(runnable); + tasks.notify(); + } + } + + public T syncExec(Callable callable) throws InterruptedException { + + if(executorThread == Thread.currentThread()) { + try { + return callable.call(); + } catch (Throwable t) { + LOGGER.error("syncExec in current thread failed", t); + return null; + } finally { + } + } + + queue(scheduleSyncExec); + + beginSyncExec.acquire(); + Thread oldThread = executorThread; + executorThread = Thread.currentThread(); + try { + return callable.call(); + } catch (Throwable t) { + LOGGER.error("syncExec failed", t); + return null; + } finally { + executorThread = oldThread; + endSyncExec.release(); + } + + } + + public void asyncExec(Runnable runnable) { + + if(executorThread == Thread.currentThread()) { + try { + runnable.run(); + } catch (Throwable t) { + LOGGER.error("asyncExec failed", t); + } finally { + } + return; + } + + queue(runnable); + + } + + public void setSimulationStepNs(long ns) { + simulationStepNs = ns; + stepInSeconds = BigDecimal.valueOf(simulationStepNs).multiply(BigDecimal.valueOf(1e-9)).doubleValue(); + } + + public void runDuration(long ns) { + runStart = System.nanoTime(); + runTimeNs = 0; + endTimeNs = ns; + synchronized(tasks) { + changeState(StandardExperimentStates.RUNNING); + tasks.notify(); + } + } + + public ExperimentState getExperimentState() { + return state; + } + + public void changeState(ExperimentState state) { + this.state = state; + fireStateChanged(state); + } + + public void addListener(DynamicExperimentThreadListener listener) { + if(!listeners.contains(listener)) + listeners.add(listener); + } + + public void removeListener(DynamicExperimentThreadListener listener) { + listeners.remove(listener); + } + + protected void fireAfterStep() { + listeners.forEach(DynamicExperimentThreadListener::afterStep); + } + + protected void fireBeforeStep() { + listeners.forEach(DynamicExperimentThreadListener::beforeStep); + } + + protected void fireStateChanged(ExperimentState newState) { + listeners.forEach(l -> l.stateChanged(newState)); + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThreadListener.java b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThreadListener.java new file mode 100644 index 000000000..18080790f --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThreadListener.java @@ -0,0 +1,13 @@ +package org.simantics.simulator.toolkit; + +import org.simantics.simulator.ExperimentState; + +/** + * @author Antti Villberg + * @since 1.34.0 + */ +public interface DynamicExperimentThreadListener { + default void beforeStep() {} + default void afterStep() {} + default void stateChanged(ExperimentState newState) {} +} \ No newline at end of file diff --git a/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThreadSequenceRunner.java b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThreadSequenceRunner.java new file mode 100644 index 000000000..2143e5a33 --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/DynamicExperimentThreadSequenceRunner.java @@ -0,0 +1,72 @@ +package org.simantics.simulator.toolkit; + +import org.eclipse.core.runtime.NullProgressMonitor; +import org.simantics.scl.runtime.SCLContext; +import org.simantics.scl.runtime.function.Function; +import org.simantics.simulator.IDynamicExperimentLocal; + +/** + * @author Antti Villberg + * @since 1.34.0 + */ +public class DynamicExperimentThreadSequenceRunner { + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static DynamicExperimentActionContext runAction(IDynamicExperimentLocal experiment, DynamicExperimentThread thread, Function action, final boolean simulateAndWaitCompletion) { + final DynamicExperimentActionContext context = new DynamicExperimentActionContext(experiment); + context.scheduleNextStep(action); + final Object sync = new Object(); + final SCLContext sclContext = SCLContext.getCurrent(); + + thread.addListener(new DynamicExperimentThreadListener() { + + @Override + public void beforeStep() { + if(!context.isStopped()) { + SCLContext.push(sclContext); + context.handleStep(experiment.getSimulationTime()); + SCLContext.pop(); + } + removeIfStopped(); + } + + public void removeIfStopped() { + if(context.isStopped()) { + thread.removeListener(this); + if(simulateAndWaitCompletion) { + experiment.simulate(false); + synchronized(sync) { + sync.notify(); + } + } + experiment.shutdown(new NullProgressMonitor()); + } + } + + }); + + if(simulateAndWaitCompletion) { + experiment.simulate(true); + + try { + synchronized(sync) { + while(!context.isStopped()) + sync.wait(1000L); + } + } catch(InterruptedException e) { + context.stop(); + } + + if (context.exceptions != null && !context.exceptions.isEmpty()) { + StringBuilder builder = new StringBuilder(); + builder.append("Action failures:"); + for (Exception e : context.exceptions) { + builder.append("\n"); + builder.append(e.getMessage()); + } + + throw new RuntimeException(builder.toString()); + } + } + return context; + } +} diff --git a/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardExperimentStates.java b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardExperimentStates.java new file mode 100644 index 000000000..c314643db --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardExperimentStates.java @@ -0,0 +1,124 @@ +package org.simantics.simulator.toolkit; + +import org.simantics.simulator.ExperimentState; + +/** + * @author Antti Villberg + * @since 1.34.0 + */ +public class StandardExperimentStates implements ExperimentState { + + /** + * The experiment context has been created. + * + *

+ * Allowed successor states: {@link Instantiated}, {@link ToBeDisposed} + */ + public interface Created extends ExperimentState {} + + /** + * The experiment context has been instantiated, i.e. underlying experimentation + * resources have been acquired. Some experiment setup (e.g. setting certain + * values) can be done in this state that cannot be touched once the experiment + * is initialized. + * + *

+ * Allowed successor states: {@link Initializing}, {@link ToBeDisposed} + */ + public interface Instantiated extends ExperimentState {} + + /** + * The experiment context is in the process of being initialized. This means + * that any initial conditions or related data is being loaded into the + * simulator/solver/what ever system that runs the experiment. + * + * If the initialization fails due to an irrecoverable system error, the + * experiment shall move to {@link Failure} state. If the initialization fails + * due to a recoverable error in user input, the experiment shall move to + * {@link Instantiated} state. + * + *

+ * Allowed successor states: {@link Initialized}, {@link Instantiated}, + * {@link Failure} + */ + public interface Initializing extends ExperimentState {} + + /** + * The experiment context has been initialized, i.e. the underlying + * experimentation resources have been both acquired and initialized with a + * specific state. + * + *

+ * Allowed successor states: {@link Stopped}, {@link Running}, + * {@link ToBeDisposed} + */ + public interface Initialized extends ExperimentState {} + + /** + * The experiment shall be ran until it reaches an objective such as + * steady-state or running for a duration or until the state changes to + * {@link Stopped}. + * + *

+ * Allowed successor states: {@link Stopped}, {@link ToBeDisposed} + */ + public interface Running extends ExperimentState {} + + /** + * The experiment shall remain stopped. Everything in the experiment context + * should remain constant while in this state. + * + *

+ * Allowed successor states: {@link Running}, {@link ToBeDisposed} + */ + public interface Stopped extends ExperimentState {} + + /** + * Moving into this state marks the beginning of the disposal of this + * experiment. The imminent disposal is irreversible and cannot be vetoed + * or interrupted. + * + *

+ * Allowed successor states: {@link Disposing} + */ + public interface ToBeDisposed extends ExperimentState {} + + /** + * The experiment context is being disposed, i.e. underlying experimentation + * resources are being freed and disposed of accordingly. + * + *

+ * Allowed successor states: {@link Disposing} + */ + public interface Disposing extends ExperimentState {} + + /** + * The experiment has been completely disposed and cannot any longer be used for + * anything. + * + *

+ * Allowed successor states: none, this is a final state + */ + public interface Disposed extends ExperimentState {} + + /** + * The experiment implementation has ran into a fatal failure. The experiment + * context can still be accessed at this point but the experiment can only move + * into {@link Disposed} state. + * + *

+ * Allowed successor states: {@link Disposed} + */ + public interface Failure extends ExperimentState {} + + public static final ExperimentState CREATED = new Created() {}; + public static final ExperimentState INSTANTIATED = new Instantiated() {}; + public static final ExperimentState INITIALIZING = new Initializing() {}; + public static final ExperimentState INITIALIZED = new Initialized() {}; + public static final ExperimentState RUNNING = new Running() {}; + public static final ExperimentState STOPPED = new Stopped() {}; + public static final ExperimentState TO_BE_DISPOSED = new ToBeDisposed() {}; + public static final ExperimentState DISPOSING = new Disposing() {}; + public static final ExperimentState DISPOSED = new Disposed() {}; + +} \ No newline at end of file diff --git a/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardNode.java b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardNode.java new file mode 100644 index 000000000..6d6878a2f --- /dev/null +++ b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardNode.java @@ -0,0 +1,14 @@ +package org.simantics.simulator.toolkit; + +/** + * Standard simulator variable node interface used with {@link StandardNodeManagerSupport} + * and {@link StandardNodeManager}. + * + * This used to exist in org.simantics.db.layer0 in earlier versions but was + * moved here to make it DB-independent. + * + * @author Antti Villberg + * @since 1.34.0 + */ +public interface StandardNode { +} diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardNodeManager.java b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardNodeManager.java similarity index 52% rename from bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardNodeManager.java rename to bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardNodeManager.java index c48c3f9d1..87ae4f32f 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardNodeManager.java +++ b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardNodeManager.java @@ -10,7 +10,7 @@ * VTT Technical Research Centre of Finland - initial API and implementation * Semantum Oy - initial API and implementation *******************************************************************************/ -package org.simantics.db.layer0; +package org.simantics.simulator.toolkit; import java.util.ArrayList; import java.util.List; @@ -19,19 +19,22 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import org.simantics.databoard.Bindings; +import org.simantics.databoard.adapter.AdaptException; +import org.simantics.databoard.adapter.Adapter; +import org.simantics.databoard.adapter.AdapterConstructionException; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.VariantBinding; -import org.simantics.databoard.binding.error.BindingConstructionException; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.binding.error.RuntimeBindingConstructionException; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.type.Datatype; -import org.simantics.db.exception.DatabaseException; import org.simantics.simulator.variable.NodeManager; import org.simantics.simulator.variable.Realm; import org.simantics.simulator.variable.exceptions.NoSuchNodeException; import org.simantics.simulator.variable.exceptions.NodeManagerException; import org.simantics.simulator.variable.exceptions.NotInRealmException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import gnu.trove.map.hash.THashMap; import gnu.trove.procedure.TObjectProcedure; @@ -43,12 +46,14 @@ import gnu.trove.set.hash.THashSet; * * @author Antti Villberg */ -public abstract class StandardNodeManager> implements NodeManager { - - final private Node root; - final private StandardRealm realm; +public abstract class StandardNodeManager> implements NodeManager { - final static Binding NO_BINDING = new VariantBinding() { + private static final Logger LOGGER = LoggerFactory.getLogger(StandardNodeManager.class); + + private final Node root; + private final StandardRealm realm; + + static final Binding NO_BINDING = new VariantBinding() { @Override public Object getContent(Object variant, Binding contentBinding) throws BindingException { @@ -89,149 +94,135 @@ public abstract class StandardNodeManager validInstances) throws BindingException { throw new Error(); } - + @Override public int compare(Object o1, Object o2) throws org.simantics.databoard.binding.error.RuntimeBindingException { - if(o1 == null) { - if(o2 == null) { - return 0; - } else { - return - System.identityHashCode(o2); - } - } else { - if(o2 == null) { - return System.identityHashCode(o1); - } else { - if(o1.equals(o2)) return 0; - return System.identityHashCode(o1) - System.identityHashCode(o2); - } - } + if(o1 == null) { + if(o2 == null) { + return 0; + } else { + return - System.identityHashCode(o2); + } + } else { + if(o2 == null) { + return System.identityHashCode(o1); + } else { + if(o1.equals(o2)) return 0; + return System.identityHashCode(o1) - System.identityHashCode(o2); + } + } } }; - - THashMap valueCache = new THashMap(); - protected THashMap> listeners = new THashMap>(); - + + THashMap valueCache = new THashMap<>(); + protected THashMap> listeners = new THashMap<>(); + AtomicBoolean fireNodeListenersScheduled = new AtomicBoolean(false); Runnable fireNodeListeners = new Runnable() { @Override public void run() { fireNodeListenersScheduled.set(false); - final TObjectProcedure procedure = new TObjectProcedure() { - @Override - public boolean execute(Runnable object) { - object.run(); - return true; - } + TObjectProcedure procedure = r -> { + r.run(); + return true; }; synchronized(listeners) { - listeners.forEachValue(new TObjectProcedure>() { - @Override - public boolean execute(THashSet object) { - object.forEach(procedure); - return true; - } + listeners.forEachValue(set -> { + set.forEach(procedure); + return true; }); } } }; - - Runnable clearValueCache = new Runnable() { - @Override - public void run() { - valueCache.clear(); - } - }; - + + Runnable clearValueCache = () -> valueCache.clear(); + public StandardNodeManager(StandardRealm realm, Node root) { - this.realm = realm; - this.root = root; - } - - @Override - public List getChildNames(Node node) throws NodeManagerException { - List children = getChildren(node); - ArrayList names = new ArrayList(children.size()); - for(Node child : children) - names.add(getName(child)); - return names; - } - - @Override - public List getPropertyNames(Node node) throws NodeManagerException { - List properties = getProperties(node); - ArrayList names = new ArrayList(properties.size()); - for(Node property : properties) - names.add(getName(property)); - return names; - } - - @Override - public Object getValue(Node node, String propertyName, Binding binding) - throws NodeManagerException, BindingException { - Node property = getProperty(node, propertyName); - if(property == null) - throw new NoSuchNodeException("Didn't find a property " + propertyName); - return getValue(property, binding); - } - - @Override - public void setValue(Node node, String propertyName, Object value, - Binding binding) throws NodeManagerException, BindingException { - Node property = getProperty(node, propertyName); - if(property == null) - throw new NoSuchNodeException("Didn't find a property " + propertyName); - setValue(property, value, binding); - } - - @Override - public Variant getValue(Node node) throws NodeManagerException { - Object value = getEngineValueOrCached(node); - if (value instanceof Variant) - return (Variant) value; + assert(realm != null); + assert(root != null); + this.realm = realm; + this.root = root; + } + + @Override + public List getChildNames(Node node) throws NodeManagerException { + List children = getChildren(node); + ArrayList names = new ArrayList<>(children.size()); + for(Node child : children) + names.add(getName(child)); + return names; + } + + @Override + public List getPropertyNames(Node node) throws NodeManagerException { + List properties = getProperties(node); + ArrayList names = new ArrayList<>(properties.size()); + for(Node property : properties) + names.add(getName(property)); + return names; + } + + @Override + public Object getValue(Node node, String propertyName, Binding binding) + throws NodeManagerException, BindingException { + Node property = getProperty(node, propertyName); + if(property == null) + throw new NoSuchNodeException("Didn't find a property " + propertyName); + return getValue(property, binding); + } + + @Override + public void setValue(Node node, String propertyName, Object value, + Binding binding) throws NodeManagerException, BindingException { + Node property = getProperty(node, propertyName); + if(property == null) + throw new NoSuchNodeException("Didn't find a property " + propertyName); + setValue(property, value, binding); + } + + @Override + public Variant getValue(Node node, String propertyName) + throws NodeManagerException { + Node property = getProperty(node, propertyName); + if(property == null) + throw new NoSuchNodeException("Didn't find a property " + propertyName); + return getValue(property); + } + + @Override + public Object getValue(Node node, Binding binding) throws NodeManagerException, BindingException { try { - Binding binding = Bindings.getBinding(value.getClass()); - return new Variant(binding, value); - } catch (BindingConstructionException e) { - e.printStackTrace(); - return null; + return getValue(node).getValue(binding); + } catch (AdaptException e) { + throw new BindingException(e); } - } - - @Override - public Variant getValue(Node node, String propertyName) - throws NodeManagerException { - Node property = getProperty(node, propertyName); - if(property == null) - throw new NoSuchNodeException("Didn't find a property " + propertyName); - return getValue(property); - } - + } + @Override public String getPropertyURI(Node parent, Node property) { return null; } - + @Override public Realm getRealm() { - return realm; + return realm; } - + public StandardRealm getStandardRealm() { - return realm; + return realm; } - + protected String getRealmId() { - return realm.getId(); + return realm.getId(); } - + public Node getRoot() { - return root; + return root; } - + protected boolean isRoot(Node node) { - return root.equals(node); + return root.equals(node); } @Override @@ -239,7 +230,7 @@ public abstract class StandardNodeManager l = listeners.get(node); if(l == null) { - l = new THashSet(); + l = new THashSet<>(); listeners.put(node, l); } l.add(listener); @@ -258,18 +249,18 @@ public abstract class StandardNodeManager map = realm.getEngine().getChildren(node); - return map.get(name); + Map map = realm.getEngine().getChildren(node); + return map.get(name); } @Override public Node getProperty(Node node, String name) throws NodeManagerException { - checkThreadAccess(); - Map map = realm.getEngine().getProperties(node); - return map.get(name); + checkThreadAccess(); + Map map = realm.getEngine().getProperties(node); + return map.get(name); } @Override @@ -373,10 +379,10 @@ public abstract class StandardNodeManager + */ +public interface StandardNodeManagerSupport { + + Object getEngineValue(Node node) throws NodeManagerException; + Binding getEngineBinding(Node node) throws NodeManagerException; + void setEngineValue(Node node, Object value) throws NodeManagerException; + String getName(Node node); + Map getChildren(Node node); + Map getProperties(Node node); + +} diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardRealm.java b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardRealm.java similarity index 87% rename from bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardRealm.java rename to bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardRealm.java index 68d002458..e228b603d 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/StandardRealm.java +++ b/bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardRealm.java @@ -1,7 +1,6 @@ -package org.simantics.db.layer0; +package org.simantics.simulator.toolkit; import java.util.List; -import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadFactory; @@ -9,24 +8,27 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.function.Function; -import org.simantics.db.common.utils.Logger; import org.simantics.scl.runtime.SCLContext; import org.simantics.scl.runtime.tuple.Tuple0; import org.simantics.simulator.variable.Realm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -abstract public class StandardRealm> implements Realm { +abstract public class StandardRealm> implements Realm { + + private static final Logger LOGGER = LoggerFactory.getLogger(StandardRealm.class); private String id; - private Thread executorThread; + protected Thread executorThread; private StandardRealmThreadFactory factory = new StandardRealmThreadFactory(this); private ThreadPoolExecutor executor = new ThreadPoolExecutor(0, 1, 60, TimeUnit.SECONDS, - new LinkedBlockingQueue(), factory); + new LinkedBlockingQueue<>(), factory); private Semaphore beginSyncExec = new Semaphore(0); private Semaphore endSyncExec = new Semaphore(0); - + private Engine engine; - private StandardNodeManager nodeManager; - + protected StandardNodeManager nodeManager; + private Runnable scheduleSyncExec = new Runnable() { @Override public void run() { @@ -37,7 +39,7 @@ abstract public class StandardRealm> i } } }; - + protected StandardRealm(Engine engine, String id) { this.engine = engine; this.id = id; @@ -45,15 +47,15 @@ abstract public class StandardRealm> i } abstract protected StandardNodeManager createManager(); - + protected String getSCLContextKey() { - return getClass().getSimpleName(); + return getClass().getSimpleName(); } public String getId() { return id; } - + public Engine getEngine() { return engine; } @@ -61,14 +63,13 @@ abstract public class StandardRealm> i public Thread getThread() { return executorThread; } - + @SuppressWarnings({ "rawtypes", "unchecked" }) public Object syncExec(Function fun) throws InterruptedException { - executor.execute(scheduleSyncExec); SCLContext context = SCLContext.getCurrent(); Engine oldConnection = (Engine)context.put(getSCLContextKey(), engine); - + try { beginSyncExec.acquire(); Thread oldThread = executorThread; @@ -83,7 +84,7 @@ abstract public class StandardRealm> i context.put(getSCLContextKey(), oldConnection); } } - + @SuppressWarnings("rawtypes") public void asyncExec(final Function fun) { executor.execute(new Runnable() { @@ -99,26 +100,25 @@ abstract public class StandardRealm> i @Override public void syncExec(Runnable runnable) throws InterruptedException { - if(executorThread == Thread.currentThread()) { try { runnable.run(); } catch (Throwable t) { - Logger.defaultLogError(t); + LOGGER.error("Error executing runnable in realm", t); } finally { } return; } - executor.execute(scheduleSyncExec); - + executor.execute(scheduleSyncExec); + beginSyncExec.acquire(); Thread oldThread = executorThread; executorThread = Thread.currentThread(); try { runnable.run(); } catch (Throwable t) { - Logger.defaultLogError(t); + LOGGER.error("Error executing runnable in realm", t); } finally { executorThread = oldThread; endSyncExec.release(); @@ -127,20 +127,19 @@ abstract public class StandardRealm> i @Override public void asyncExec(Runnable runnable) { - - if(executorThread == Thread.currentThread()) { + if(executorThread == Thread.currentThread()) { try { runnable.run(); } catch (Throwable t) { - Logger.defaultLogError(t); + LOGGER.error("Error executing runnable in realm", t); } finally { } return; } - + executor.execute(runnable); } - + public void close() { executor.shutdown(); try { @@ -153,7 +152,7 @@ abstract public class StandardRealm> i } catch (InterruptedException e) { getLogger().info("Could not shutdown executor " + executor + " for realm " + this, e); } - + factory.clear(); factory = null; // Should never be true @@ -161,7 +160,7 @@ abstract public class StandardRealm> i executorThread.interrupt(); executorThread = null; executor = null; - + // Clear nodeManager nodeManager.clear(); nodeManager = null; @@ -178,22 +177,23 @@ abstract public class StandardRealm> i } private static class StandardRealmThreadFactory implements ThreadFactory { - + private StandardRealm realm; public StandardRealmThreadFactory(StandardRealm realm) { this.realm = realm; } - + @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); realm.setExecutorThread(t); return t; } - + void clear() { realm = null; } } -} + +} \ No newline at end of file diff --git a/bundles/org.simantics.simulator/.classpath b/bundles/org.simantics.simulator/.classpath new file mode 100644 index 000000000..b862a296d --- /dev/null +++ b/bundles/org.simantics.simulator/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.simantics.simulator/.project b/bundles/org.simantics.simulator/.project new file mode 100644 index 000000000..2487735c0 --- /dev/null +++ b/bundles/org.simantics.simulator/.project @@ -0,0 +1,28 @@ + + + org.simantics.simulator + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/bundles/org.simantics.simulator/META-INF/MANIFEST.MF b/bundles/org.simantics.simulator/META-INF/MANIFEST.MF new file mode 100644 index 000000000..fb5601090 --- /dev/null +++ b/bundles/org.simantics.simulator/META-INF/MANIFEST.MF @@ -0,0 +1,10 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Simulator +Bundle-SymbolicName: org.simantics.simulator +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.slf4j.api;bundle-version="1.7.25", + org.eclipse.core.runtime, + org.simantics.databoard;bundle-version="0.6.6" +Export-Package: org.simantics.simulator diff --git a/bundles/org.simantics.simulator/build.properties b/bundles/org.simantics.simulator/build.properties new file mode 100644 index 000000000..41eb6ade2 --- /dev/null +++ b/bundles/org.simantics.simulator/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/bundles/org.simantics.simulator/src/org/simantics/simulator/ExperimentState.java b/bundles/org.simantics.simulator/src/org/simantics/simulator/ExperimentState.java new file mode 100644 index 000000000..6f041538d --- /dev/null +++ b/bundles/org.simantics.simulator/src/org/simantics/simulator/ExperimentState.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2018 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.simulator; + +/** + * An abstract representation of the state of an experiment. + * + *

+ * A standard set of states can be found in + * org.simantics.simulator.toolkit.StandardExperimentStates. + * + * @author Antti Villberg + * @since 1.34.0 + */ +public interface ExperimentState { +} \ No newline at end of file diff --git a/bundles/org.simantics.simulator/src/org/simantics/simulator/IDynamicExperimentLocal.java b/bundles/org.simantics.simulator/src/org/simantics/simulator/IDynamicExperimentLocal.java new file mode 100644 index 000000000..2d3002db2 --- /dev/null +++ b/bundles/org.simantics.simulator/src/org/simantics/simulator/IDynamicExperimentLocal.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2018 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.simulator; + +import org.simantics.databoard.binding.Binding; + +public interface IDynamicExperimentLocal extends IExperimentLocal { + + /** + * Starts or stops simulation depending on the + * parameter. + */ + public void simulate(boolean enabled); + + /** + * Simulates the experiment at lest the given period of time. + * Giving 0 as parameter simulates the experiment one 'step'. + * After the duration, the simulation is stopped. + */ + public void simulateDuration(double duration); + + void setVariableValueById(String id, Object value, Binding binding); + Object getVariableValueById(String id); + + double getSimulationTime(); + +} diff --git a/bundles/org.simantics.simulator/src/org/simantics/simulator/IExperimentLocal.java b/bundles/org.simantics.simulator/src/org/simantics/simulator/IExperimentLocal.java new file mode 100644 index 000000000..addfbcf6b --- /dev/null +++ b/bundles/org.simantics.simulator/src/org/simantics/simulator/IExperimentLocal.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2018 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.simulator; + +import org.eclipse.core.runtime.IProgressMonitor; + +public interface IExperimentLocal { + + T getService(Class clazz); + + String getIdentifier(); + + /** + * @param monitor + * the progress monitor to use for reporting progress to the user + * during the operation. It is the caller's responsibility to + * call done() on the given monitor. Accepts null, indicating + * that no progress should be reported and that the operation + * cannot be cancelled. + */ + void shutdown(IProgressMonitor monitor); + + ExperimentState getStateL(); + void changeStateL(ExperimentState state); + +} diff --git a/bundles/org.simantics.spreadsheet.graph/META-INF/MANIFEST.MF b/bundles/org.simantics.spreadsheet.graph/META-INF/MANIFEST.MF index 8ecef199d..cb7afb74d 100644 --- a/bundles/org.simantics.spreadsheet.graph/META-INF/MANIFEST.MF +++ b/bundles/org.simantics.spreadsheet.graph/META-INF/MANIFEST.MF @@ -29,7 +29,9 @@ Require-Bundle: org.simantics.layer0.utils, org.eclipse.e4.core.contexts, org.eclipse.e4.ui.di, org.simantics.browsing.ui.swt, - org.slf4j.api;bundle-version="1.7.20" + org.slf4j.api;bundle-version="1.7.20", + org.simantics.simulator.toolkit;bundle-version="1.0.0", + org.simantics.simulator.toolkit.db;bundle-version="1.0.0" Export-Package: org.apache.commons.math3.stat.regression, org.simantics.spreadsheet.graph, org.simantics.spreadsheet.graph.adapter, diff --git a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/GraphUI.java b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/GraphUI.java index 5850eb847..607661163 100644 --- a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/GraphUI.java +++ b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/GraphUI.java @@ -45,7 +45,6 @@ import org.simantics.db.common.request.WriteRequest; import org.simantics.db.common.request.WriteResultRequest; import org.simantics.db.common.session.SessionEventListenerAdapter; import org.simantics.db.exception.DatabaseException; -import org.simantics.db.layer0.StandardRealm; import org.simantics.db.layer0.request.PossibleURIVariable; import org.simantics.db.layer0.request.VariableName; import org.simantics.db.layer0.request.VariableRead; @@ -56,6 +55,7 @@ import org.simantics.db.procedure.SyncListener; import org.simantics.db.request.Write; import org.simantics.db.service.SessionEventSupport; import org.simantics.layer0.Layer0; +import org.simantics.simulator.toolkit.StandardRealm; import org.simantics.spreadsheet.Adaptable; import org.simantics.spreadsheet.CellEditor; import org.simantics.spreadsheet.ClientModel; diff --git a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetBook.java b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetBook.java index 277b10cb0..f87ce4d06 100644 --- a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetBook.java +++ b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetBook.java @@ -10,9 +10,12 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import org.simantics.databoard.Bindings; +import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.db.exception.DatabaseException; -import org.simantics.db.layer0.StandardEngine; +import org.simantics.simulator.toolkit.StandardNodeManagerSupport; +import org.simantics.simulator.variable.exceptions.NodeManagerException; import org.simantics.spreadsheet.graph.formula.SpreadsheetEvaluationEnvironment; import org.simantics.spreadsheet.graph.synchronization.LineNodeUpdater; import org.simantics.spreadsheet.graph.synchronization.LineUpdater; @@ -33,7 +36,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArraySet; import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; -public class SpreadsheetBook implements SpreadsheetElement, StandardEngine, Serializable, SheetNode, Solver, SolverNameUtil, ComponentFactory, ModuleUpdaterFactoryBase { +public class SpreadsheetBook implements StandardNodeManagerSupport, SpreadsheetElement, Serializable, SheetNode, Solver, SolverNameUtil, ComponentFactory, ModuleUpdaterFactoryBase { private static final long serialVersionUID = 7417208688311691396L; @@ -90,7 +93,17 @@ public class SpreadsheetBook implements SpreadsheetElement { - + public SpreadsheetNodeManager(SpreadsheetRealm realm) { super(realm, realm.getEngine()); } static final Set COMPONENT_CLASS = Collections.singleton(StructuralResource2.URIs.Component); - + @Override public Set getClassifications(SheetNode node) throws NodeManagerException { checkThreadAccess(); @@ -26,22 +26,22 @@ public class SpreadsheetNodeManager extends StandardNodeManager { private static final Logger LOGGER = LoggerFactory.getLogger(SpreadsheetRealm.class); - + SpreadsheetRealm(SpreadsheetBook book, String id) { super(book, id); } diff --git a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetSessionManager.java b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetSessionManager.java index d90fe3106..19c994806 100644 --- a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetSessionManager.java +++ b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetSessionManager.java @@ -15,11 +15,11 @@ import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.exception.DatabaseException; -import org.simantics.db.layer0.StandardRealm; -import org.simantics.db.layer0.StandardSessionManager; import org.simantics.db.layer0.variable.ProxyVariables; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; +import org.simantics.simulator.toolkit.StandardRealm; +import org.simantics.simulator.toolkit.db.StandardSessionManager; import org.simantics.spreadsheet.graph.formula.SpreadsheetEvaluationEnvironment; import org.simantics.spreadsheet.graph.synchronization.SpreadsheetSynchronizationEventHandler; import org.simantics.spreadsheet.resource.SpreadsheetResource; diff --git a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/function/All.java b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/function/All.java index 0affbc1c5..1439a941d 100644 --- a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/function/All.java +++ b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/function/All.java @@ -29,7 +29,6 @@ import org.simantics.db.common.request.WriteRequest; import org.simantics.db.common.utils.Logger; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; -import org.simantics.db.layer0.StandardRealm; import org.simantics.db.layer0.exception.MissingVariableException; import org.simantics.db.layer0.function.StandardChildDomainChildren; import org.simantics.db.layer0.request.PossibleActiveRun; @@ -50,6 +49,7 @@ import org.simantics.document.server.io.IFont; import org.simantics.document.server.io.ITableCell; import org.simantics.layer0.Layer0; import org.simantics.scl.reflection.annotations.SCLValue; +import org.simantics.simulator.toolkit.StandardRealm; import org.simantics.simulator.variable.exceptions.NodeManagerException; import org.simantics.spreadsheet.CellEditor; import org.simantics.spreadsheet.ClientModel; diff --git a/bundles/pom.xml b/bundles/pom.xml index 43a6f72ab..59ac14535 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -201,6 +201,9 @@ org.simantics.simulation.ontology org.simantics.simulation.sequences org.simantics.simulation.ui + org.simantics.simulator + org.simantics.simulator.toolkit + org.simantics.simulator.toolkit.db org.simantics.simulator.variable org.simantics.softwareconfiguration.ontology org.simantics.spreadsheet diff --git a/features/org.simantics.sdk.feature/feature.xml b/features/org.simantics.sdk.feature/feature.xml index 5aeb671c8..b9e8cfcfc 100644 --- a/features/org.simantics.sdk.feature/feature.xml +++ b/features/org.simantics.sdk.feature/feature.xml @@ -204,6 +204,14 @@ id="org.simantics.scl.ui.feature" version="0.0.0"/> + + + + + + org.simantics.simulator.toolkit.db.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/features/org.simantics.simulator.toolkit.db.feature/build.properties b/features/org.simantics.simulator.toolkit.db.feature/build.properties new file mode 100644 index 000000000..82ab19c62 --- /dev/null +++ b/features/org.simantics.simulator.toolkit.db.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/features/org.simantics.simulator.toolkit.db.feature/feature.xml b/features/org.simantics.simulator.toolkit.db.feature/feature.xml new file mode 100644 index 000000000..875116394 --- /dev/null +++ b/features/org.simantics.simulator.toolkit.db.feature/feature.xml @@ -0,0 +1,31 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + diff --git a/features/org.simantics.simulator.toolkit.feature/.project b/features/org.simantics.simulator.toolkit.feature/.project new file mode 100644 index 000000000..241fafebd --- /dev/null +++ b/features/org.simantics.simulator.toolkit.feature/.project @@ -0,0 +1,17 @@ + + + org.simantics.simulator.toolkit.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/features/org.simantics.simulator.toolkit.feature/build.properties b/features/org.simantics.simulator.toolkit.feature/build.properties new file mode 100644 index 000000000..82ab19c62 --- /dev/null +++ b/features/org.simantics.simulator.toolkit.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/features/org.simantics.simulator.toolkit.feature/feature.xml b/features/org.simantics.simulator.toolkit.feature/feature.xml new file mode 100644 index 000000000..79c4b2cd3 --- /dev/null +++ b/features/org.simantics.simulator.toolkit.feature/feature.xml @@ -0,0 +1,62 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + + + + + + + + + diff --git a/features/org.simantics.spreadsheet.ui.feature/feature.xml b/features/org.simantics.spreadsheet.ui.feature/feature.xml index b81d38a3b..33385bcaa 100644 --- a/features/org.simantics.spreadsheet.ui.feature/feature.xml +++ b/features/org.simantics.spreadsheet.ui.feature/feature.xml @@ -25,6 +25,10 @@ id="org.simantics.scl" version="0.0.0"/> + + org.simantics.sdk.feature org.simantics.selectionview.feature org.simantics.simulation.feature + org.simantics.simulator.toolkit.feature + org.simantics.simulator.toolkit.db.feature org.simantics.spreadsheet.feature org.simantics.spreadsheet.ui.feature org.simantics.structural.feature -- 2.43.2