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 { private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(StateNodeManager.class); private NodeSupport support; public StateNodeManager(StandardRealm realm, StateNode root) { super(realm, root); } public void registerSupport(NodeSupport support) { this.support = support; } @Override public Set 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 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); } } }