org.simantics.modeling;bundle-version="1.1.1",
org.simantics.document.server.io;visibility:=reexport,
org.simantics.scl.db;bundle-version="0.1.3",
- org.slf4j.api
+ org.slf4j.api,
+ org.simantics.simulator.toolkit,
+ org.simantics.simulator.toolkit.db;visibility:=reexport
Bundle-ActivationPolicy: lazy
Bundle-Activator: org.simantics.document.server.Activator
Export-Package: org.simantics.document.server,
org.simantics.document.server.client,
org.simantics.document.server.handler,
org.simantics.document.server.request,
- org.simantics.document.server.serverResponse
+ org.simantics.document.server.serverResponse,
+ org.simantics.document.server.state
Import-Package: org.simantics.layer0.utils.direct
Bundle-ClassPath: .
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2007, 2010 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:
+ VTT Technical Research Centre of Finland - initial API and implementation
+ -->
+
+<adapters>
+ <target interface="org.simantics.db.layer0.variable.VariableBuilder">
+ <type uri="http://www.simantics.org/Modeling-1.2/SCLCommandSession" class="org.simantics.document.server.state.StateVariableBuilder" />
+ </target>
+</adapters>
\ No newline at end of file
.,\
plugin.xml,\
webdefault.xml,\
- scl/
+ scl/,\
+ adapters.xml
src.includes = scl/
source.. = src/
import org.simantics.document.server.request.ServerSCLValueRequest;
import org.simantics.document.server.serverResponse.ServerResponse;
import org.simantics.document.server.serverResponse.SuccessResponse;
+import org.simantics.document.server.state.StateNodeManager;
+import org.simantics.document.server.state.StateRealm;
+import org.simantics.document.server.state.StateSessionManager;
import org.simantics.modeling.ModelingResources;
import org.simantics.modeling.scl.SCLRealm;
import org.simantics.modeling.scl.SCLSessionManager;
} else {
- String id = sclStateKey(graph, base, self, ref);
-
- SCLRealm realm = SCLSessionManager.getOrCreateSCLRealm(base.getURI(graph) + "/__scl__");
- realm.getConnection().setVariable(id, getSCLType(defaultValue), defaultValue);
-
return defaultValue;
}
String id = sclStateKey(graph, base, self, ref);
- SCLRealm realm = SCLSessionManager.getOrCreateSCLRealm(base.getURI(graph)+"/__scl__");
- realm.getConnection().setVariable(id, getSCLType(value), value);
- realm.refreshVariablesSync();
+ StateRealm realm = (StateRealm) StateSessionManager.getInstance().getOrCreateRealm(graph, base.getURI(graph)+"/__scl__");
+ StateNodeManager nodeManager = (StateNodeManager) realm.getNodeManager();
+ nodeManager.setState(id, value);
}
--- /dev/null
+package org.simantics.document.server.state;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.binding.mutable.Variant;
+
+public class State {
+ public static final Binding BINDING = Bindings.getBindingUnchecked(State.class);
+ public Map<String, Variant> properties = new TreeMap<>();
+}
--- /dev/null
+package org.simantics.document.server.state;
+
+import org.simantics.simulator.toolkit.StandardNode;
+
+public class StateNode implements StandardNode {
+
+}
--- /dev/null
+package org.simantics.document.server.state;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.binding.error.BindingConstructionException;
+import org.simantics.databoard.binding.mutable.Variant;
+import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;
+import org.simantics.databoard.serialization.SerializerConstructionException;
+import org.simantics.db.layer0.variable.NodeSupport;
+import org.simantics.simulator.toolkit.StandardNodeManager;
+import org.simantics.simulator.toolkit.StandardRealm;
+import org.simantics.simulator.variable.exceptions.NodeManagerException;
+import org.slf4j.LoggerFactory;
+
+public class StateNodeManager extends StandardNodeManager<StateNode, StateNodeManagerSupport> {
+
+ private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(StateNodeManager.class);
+
+ private NodeSupport<StateNode> support;
+
+ public StateNodeManager(StandardRealm<StateNode, StateNodeManagerSupport> realm, StateNode root) {
+ super(realm, root);
+ }
+
+ public void registerSupport(NodeSupport<StateNode> support) {
+ this.support = support;
+ }
+
+ @Override
+ public Set<String> getClassifications(StateNode node) throws NodeManagerException {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public void refreshVariable(StateNode node) {
+ super.refreshVariable(node);
+ support.valueCache.clearExpired();
+ support.structureCache.clearExpired();
+ }
+
+ public void setState(String key, Object value) {
+ try {
+ getRealm().syncExec(() -> {
+ try {
+ StateRootNode rootNode = (StateRootNode) getRoot();
+ StatePropertyNode propertyNode = rootNode.getProperty(key);
+ if (propertyNode == null) {
+ setValue(rootNode.createProperty(key), value, Bindings.OBJECT);
+ refreshVariable(rootNode);
+ } else {
+ setValue(propertyNode, value, Bindings.OBJECT);
+ }
+ } catch (NodeManagerException e) {
+ LOGGER.error("Failed to set state.", e);
+ }
+ });
+ } catch (InterruptedException e) {
+ LOGGER.error("Setting state was interrupted.", e);
+ }
+ }
+
+ public byte[] serialize() {
+ final byte [][] result = new byte[1][];
+ try {
+ getRealm().syncExec(() -> {
+ State state = new State();
+ StateRootNode root = (StateRootNode) getRoot();
+ for (StateNode node : root.getProperties().values()) {
+ StatePropertyNode property = (StatePropertyNode)node;
+ try {
+ Binding binding = Bindings.getInstanceBinding(property.getValue());
+ if (binding != null) {
+ state.properties.put(property.getName(), new Variant(binding, property.getValue()));
+ }
+ } catch (BindingConstructionException e) {
+ // skip
+ }
+ }
+
+ try {
+ result[0] = Bindings.getSerializerUnchecked(State.BINDING).serialize(state);
+ } catch (RuntimeSerializerConstructionException | IOException e) {
+ }
+ });
+ } catch (InterruptedException e) {
+ LOGGER.error("Serializing state was interrupted.", e);
+ }
+ return result[0];
+ }
+
+ public void deserialize(byte[] bytes) {
+ try {
+ getRealm().syncExec(() -> {
+ StateRootNode rootNode = (StateRootNode) getRoot();
+ rootNode.clear();
+ try {
+ State state = (State) Bindings.getSerializer(State.BINDING).deserialize(bytes);
+ for (Map.Entry<String, Variant> entry : state.properties.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue().getValue();
+ try {
+ setValue(rootNode.createProperty(key), value, Bindings.OBJECT);
+ } catch (NodeManagerException e) {
+ LOGGER.error("Failed to deserialize state.", e);
+ }
+ }
+ refreshVariable(rootNode);
+ } catch (IOException e1) {
+ LOGGER.error("Failed to deserialize state.", e1);
+ } catch (SerializerConstructionException e1) {
+ LOGGER.error("Failed to deserialize state.", e1);
+ }
+ });
+ } catch (InterruptedException e) {
+ LOGGER.error("Deserializing state was interrupted.", e);
+ }
+ }
+
+ public void clearState() {
+ try {
+ getRealm().syncExec(() -> {
+ StateRootNode rootNode = (StateRootNode) getRoot();
+ rootNode.clear();
+ refreshVariable(rootNode);
+ });
+ } catch (InterruptedException e) {
+ LOGGER.error("Clearing state was interrupted.", e);
+ }
+ }
+
+ public void removeState(String key) {
+ try {
+ getRealm().syncExec(() -> {
+ StateRootNode rootNode = (StateRootNode) getRoot();
+ if (rootNode.removeProperty(key)) {
+ refreshVariable(rootNode);
+ }
+ });
+ } catch (InterruptedException e) {
+ LOGGER.error("Removing state was interrupted.", e);
+ }
+ }
+
+}
--- /dev/null
+package org.simantics.document.server.state;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.simulator.toolkit.StandardNodeManagerSupport;
+import org.simantics.simulator.variable.exceptions.NoValueException;
+import org.simantics.simulator.variable.exceptions.NodeManagerException;
+
+public class StateNodeManagerSupport implements StandardNodeManagerSupport<StateNode> {
+
+ @Override
+ public Object getEngineValue(StateNode node) throws NodeManagerException {
+ if (node instanceof StatePropertyNode) {
+ return ((StatePropertyNode) node).getValue();
+ }
+ else throw new NoValueException();
+ }
+
+ @Override
+ public Binding getEngineBinding(StateNode node) throws NodeManagerException {
+ if (node instanceof StatePropertyNode) {
+ return Bindings.OBJECT;
+ }
+ else throw new NoValueException();
+ }
+
+ @Override
+ public void setEngineValue(StateNode node, Object value) throws NodeManagerException {
+ if (node instanceof StatePropertyNode) {
+ ((StatePropertyNode) node).setValue(value);
+ }
+ else throw new NodeManagerException();
+ }
+
+ @Override
+ public String getName(StateNode node) {
+ if (node instanceof StatePropertyNode) {
+ return ((StatePropertyNode) node).getName();
+ } else return "@";
+ }
+
+ @Override
+ public Map<String, StateNode> getChildren(StateNode node) {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public Map<String, StateNode> getProperties(StateNode node) {
+ if (node instanceof StateRootNode) {
+ return ((StateRootNode) node).getProperties();
+ } else return Collections.emptyMap();
+ }
+
+}
--- /dev/null
+package org.simantics.document.server.state;
+
+public class StatePropertyNode extends StateNode {
+
+ public String name;
+ public Object value;
+
+ public StatePropertyNode(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+}
--- /dev/null
+package org.simantics.document.server.state;
+
+import java.util.function.Function;
+
+import org.simantics.simulator.toolkit.StandardNodeManager;
+import org.simantics.simulator.toolkit.StandardRealm;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class StateRealm extends StandardRealm<StateNode, StateNodeManagerSupport> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(StateRealm.class);
+
+ protected StateRealm(StateNodeManagerSupport engine, String id) {
+ super(engine, id);
+ }
+
+ @Override
+ public Logger getLogger() {
+ return LOGGER;
+ }
+
+ @Override
+ protected StandardNodeManager<StateNode, StateNodeManagerSupport> createManager() {
+ return new StateNodeManager(this, new StateRootNode());
+ }
+
+ @Override
+ public void asyncExec(Function fun) {
+ try {
+ syncExec(fun);
+ } catch (InterruptedException e) {
+ LOGGER.error("Execution interrupted.", e);
+ }
+ }
+
+ @Override
+ public void asyncExec(Runnable runnable) {
+ try {
+ syncExec(runnable);
+ } catch (InterruptedException e) {
+ LOGGER.error("Execution interrupted.", e);
+ }
+ }
+
+}
--- /dev/null
+package org.simantics.document.server.state;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+public class StateRootNode extends StateNode {
+
+ public Map<String, StateNode> properties = new TreeMap<>();
+
+ public Map<String, StateNode> getProperties() {
+ return properties;
+ }
+
+ public StatePropertyNode getProperty(String key) {
+ return (StatePropertyNode) properties.get(key);
+ }
+
+ public StatePropertyNode createProperty(String key) {
+ StatePropertyNode propertyNode = new StatePropertyNode(key);
+ properties.put(key, propertyNode);
+ return propertyNode;
+ }
+
+ public boolean removeProperty(String key) {
+ return (properties.remove(key) != null);
+ }
+
+ public void clear() {
+ properties.clear();
+ }
+
+}
--- /dev/null
+package org.simantics.document.server.state;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.variable.NodeSupport;
+import org.simantics.simulator.toolkit.StandardNodeManager;
+import org.simantics.simulator.toolkit.StandardRealm;
+import org.simantics.simulator.toolkit.db.StandardSessionManager;
+
+public class StateSessionManager extends StandardSessionManager<StateNode, StateNodeManagerSupport> {
+
+ private static StateSessionManager INSTANCE;
+
+ public static StateSessionManager getInstance() {
+ if(INSTANCE == null) {
+ INSTANCE = new StateSessionManager();
+ }
+ return INSTANCE;
+ }
+
+ @Override
+ protected StateNodeManagerSupport createEngine(ReadGraph graph, String id) throws DatabaseException {
+ return new StateNodeManagerSupport();
+ }
+
+ @Override
+ protected StandardRealm<StateNode, StateNodeManagerSupport> createRealm(StateNodeManagerSupport engine, String id) {
+ return new StateRealm(engine, id);
+ }
+
+ @Override
+ public void registerNodeSupport(StandardNodeManager<StateNode, StateNodeManagerSupport> manager,
+ NodeSupport<StateNode> support) {
+ ((StateNodeManager)manager).registerSupport(support);
+ }
+
+}
--- /dev/null
+package org.simantics.document.server.state;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.variable.NodeManagerVariableBuilder;
+import org.simantics.db.layer0.variable.NodeSupport;
+import org.simantics.document.server.state.StateNodeManager;
+import org.simantics.document.server.state.StateSessionManager;
+
+public class StateVariableBuilder extends NodeManagerVariableBuilder {
+
+ @Override
+ protected NodeSupport<?> getNodeSupport(ReadGraph graph, String sessionName) throws DatabaseException {
+ return StateSessionManager.getInstance().getOrCreateNodeSupport(graph, sessionName);
+ }
+
+ @Override
+ protected Object getRoot(ReadGraph graph, NodeSupport<?> support, String sessionName) {
+ StateNodeManager manager = (StateNodeManager)support.manager;
+ return manager.getRoot();
+ }
+
+}
\ No newline at end of file
</type>
</target>
-
- <target interface="org.simantics.db.layer0.variable.VariableBuilder">
- <type uri="http://www.simantics.org/Modeling-1.2/SCLCommandSession" class="org.simantics.modeling.scl.SCLVariableBuilder" />
- </target>
-
<target interface="org.simantics.db.layer0.migration.MigrationStep">
<resource uri="http://www.simantics.org/Modeling-1.2/Migration/attachCreationInformationStep"
class="org.simantics.modeling.migration.AttachCreationInformationStep"
import org.simantics.db.exception.DatabaseException;
import org.simantics.db.layer0.variable.NodeSupport;
import org.simantics.db.procedure.Listener;
+import org.simantics.simulator.toolkit.StandardNodeManager;
import org.simantics.simulator.toolkit.StandardNodeManagerSupport;
import org.simantics.simulator.toolkit.StandardRealm;
}
}
+ public void registerNodeSupport(StandardNodeManager<Node,Engine> realm, NodeSupport<Node> support) {
+
+ }
+
public NodeSupport<Node> getOrCreateNodeSupport(ReadGraph graph, String id) throws DatabaseException {
synchronized(SUPPORTS) {
NodeSupport<Node> result = SUPPORTS.get(id);
if(result == null) {
StandardRealm<Node,Engine> realm = getOrCreateRealm(graph, id);
result = new NodeSupport<Node>(realm.getNodeManager());
+ registerNodeSupport(realm.getNodeManager(), result);
SUPPORTS.put(id, result);
}
return result;
/**
* StandardNodeManager gives default implementations to some methods
* of NodeManager.
- *
+ *
* @author Antti Villberg
*/
public abstract class StandardNodeManager<Node, Engine extends StandardNodeManagerSupport<Node>> implements NodeManager<Node> {
return System.identityHashCode(o1);
} else {
if(o1.equals(o2)) return 0;
- return System.identityHashCode(o1) - System.identityHashCode(o2);
+ return System.identityHashCode(o1) - System.identityHashCode(o2);
}
}
}
};
- THashMap<Node, Variant> valueCache = new THashMap<>();
- protected THashMap<Node, THashSet<Runnable>> listeners = new THashMap<>();
+ THashMap<Node, Variant> valueCache = new THashMap<>();
+ protected THashMap<Node, THashSet<Runnable>> listeners = new THashMap<>();
AtomicBoolean fireNodeListenersScheduled = new AtomicBoolean(false);
Runnable fireNodeListeners = new Runnable() {
}
};
- Runnable clearValueCache = () -> valueCache.clear();
+ Runnable clearValueCache = () -> valueCache.clear();
public StandardNodeManager(StandardRealm<Node,Engine> realm, Node root) {
assert(realm != null);
}
}
+ public void refreshVariable(Node node) {
+ realm.asyncExec(() -> {
+ valueCache.remove(node);
+ synchronized(listeners) {
+ THashSet<Runnable> runnables = listeners.get(node);
+ if (runnables != null) {
+ for (Runnable r : runnables) {
+ r.run();
+ }
+ }
+ }
+ });
+ }
+
public void refreshVariables() {
realm.asyncExec(clearValueCache);
fireNodeListeners();
throw new NodeManagerException(e);
}
}
- refreshVariables();
+ refreshVariable(node);
}
@Override
String id = getRealmId();
int lastSlash = id.lastIndexOf("/");
if(lastSlash == -1) throw new IllegalStateException("Invalid realm id " + id);
- String name = id.substring(lastSlash+1);
+ String name = id.substring(lastSlash+1);
return name;
} else {
return realm.getEngine().getName(node);