1 package org.simantics.db.layer0.variable;
3 import org.simantics.databoard.binding.Binding;
4 import org.simantics.databoard.binding.error.BindingException;
5 import org.simantics.databoard.binding.mutable.Variant;
6 import org.simantics.databoard.util.ObjectUtils;
7 import org.simantics.db.ReadGraph;
8 import org.simantics.db.common.request.ParametrizedPrimitiveRead;
9 import org.simantics.db.exception.DatabaseException;
10 import org.simantics.db.procedure.Listener;
11 import org.simantics.simulator.variable.NodeManager;
12 import org.simantics.simulator.variable.exceptions.NodeIsNotValidAnymoreException;
13 import org.simantics.simulator.variable.exceptions.NodeManagerException;
14 import org.simantics.utils.datastructures.Pair;
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
18 @SuppressWarnings("rawtypes")
19 class NodeValueRequest extends ParametrizedPrimitiveRead<Pair<VariableNode,Binding>, Variant> implements VariableNodeReadRunnable {
21 private static final Logger LOGGER = LoggerFactory.getLogger(NodeValueRequest.class);
23 private Listener<Variant> listener = null;
24 private Variant value = Variables.PENDING_NODE_VALUE;
25 private boolean wasRun = false;
27 static class Probe implements Runnable {
29 private Pair<VariableNode,Binding> parameter;
30 public Variant result;
32 public Probe(Pair<VariableNode,Binding> parameter) {
33 this.parameter = parameter;
36 @SuppressWarnings("unchecked")
40 result = NodeValueRequest.get(parameter);
41 parameter.first.support.valueCache.put(parameter.first.node, result, 1000000000L);
42 } catch (NodeManagerException e) {
44 } catch (BindingException e) {
51 public NodeValueRequest(VariableNode node) {
52 super(Pair.<VariableNode, Binding>make(node, null));
55 public NodeValueRequest(VariableNode node, Binding binding) {
56 super(Pair.<VariableNode, Binding>make(node, binding));
59 @SuppressWarnings("unchecked")
61 public void register(ReadGraph graph, final Listener<Variant> procedure) {
63 VariableNode node = parameter.first;
65 if(procedure.isDisposed()) {
67 // We are not listening
68 Variant result = (Variant)node.support.valueCache.get(node.node);
71 // Return cached value immediately
72 procedure.execute(result);
76 // listener = procedure;
78 // if(graph.getSynchronous()) {
80 // parameter.support.manager.getRealm().syncExec(this);
81 // } catch (InterruptedException e) {
82 // if (!wasRun) procedure.exception(e);
83 // } catch (Throwable e) {
84 // if (!wasRun) procedure.exception(e);
87 // parameter.support.manager.getRealm().asyncExec(this);
89 // if(value == Variables.PENDING_NODE_VALUE) {
90 // procedure.execute(Variables.PENDING_NODE_VALUE);
95 NodeValueRequest.Probe probe = new Probe(parameter);
96 node.support.manager.getRealm().asyncExec(probe);
97 if(probe.result != null) {
98 procedure.execute(probe.result);
100 procedure.execute(Variables.PENDING_NODE_VALUE);
109 listener = procedure;
110 // Register listening
111 node.support.manager.addNodeListener(node.node, this);
114 procedure.execute(value);
116 Variant result = (Variant)node.support.valueCache.get(node.node);
118 procedure.execute(result);
120 procedure.execute(Variables.PENDING_NODE_VALUE);
125 // if(listener != null) {
126 // throw new UnsupportedOperationException();
128 // listener = procedure;
129 // if(graph.getSynchronous()) {
131 // parameter.support.manager.getRealm().syncExec(new VariableNodeReadRunnable() {
133 // public void run() {
134 // parameter.support.manager.addNodeListener(parameter.node, NodeValueRequest.this);
137 // public String toString() {
138 // return "NodeValueRequest.register.sync.addNodeListener @ " + System.identityHashCode(NodeValueRequest.this);
142 // if (!wasRun) procedure.exception(new InternalException("No invocation of listener from node manager " + parameter.support.manager.getClass().getName()));
143 // } catch (InterruptedException e) {
144 // if (!wasRun) procedure.exception(e);
145 // } catch (Throwable e) {
146 // if (!wasRun) procedure.exception(e);
149 // parameter.support.manager.addNodeListener(parameter.node, this);
150 // if(value == Variables.PENDING_NODE_VALUE) procedure.execute(Variables.PENDING_NODE_VALUE);
155 static class NodeListener implements VariableNodeReadRunnable {
157 private VariableNode node;
158 private NodeValueRequest request;
160 public NodeListener(VariableNode node, NodeValueRequest request) {
162 this.request = request;
165 @SuppressWarnings("unchecked")
168 node.support.manager.addNodeListener(node.node, request);
174 @SuppressWarnings("unchecked")
176 public void unregistered() {
177 VariableNode node = parameter.first;
178 node.support.manager.removeNodeListener(node.node, this);
179 node.support.valueCache.removeListening(node.node);
183 @SuppressWarnings("unchecked")
184 public static Variant get(Pair<VariableNode,Binding> parameter) throws NodeManagerException, BindingException {
186 VariableNode node = parameter.first;
187 Binding binding = parameter.second;
189 if (binding != null) {
190 Object raw = node.support.manager.getValue(node.node, binding);
193 else if(NodeManager.PENDING_NODE_VALUE == raw)
194 return NodeManager.PENDING_NODE_VALUE;
195 else return new Variant(binding, raw);
197 return node.support.manager.getValue(node.node);
202 @SuppressWarnings("unchecked")
204 public synchronized void run() {
206 VariableNode node = parameter.first;
209 Variant newValue = get(parameter);
210 if (wasRun && ObjectUtils.objectEquals(value, newValue)) {
211 //System.out.println("CACHE VALUE MATCH (" + newValue + ") for " + node.node);
215 node.support.valueCache.put(node.node, value);
216 } catch (Throwable e) {
217 // Must catch everything to prevent DB client from getting stuck.
218 if(!(e instanceof NodeIsNotValidAnymoreException))
219 LOGGER.error("Error while computing node value", e);
220 // Invoke the exception method of the listener
221 Listener<Variant> listener = this.listener;
222 if (listener != null) listener.exception(new DatabaseException("External data access error", e));
226 // Must always invoke an existing listener, regardless of earlier errors.
227 Listener<Variant> listener = this.listener;
228 if (listener != null) {
229 //System.out.println("LISTENER " + listener + " invoked with value " + value);
230 listener.execute(value);
236 public String toString() {
237 return "NodeValueRequest.run " + parameter.first.node + " " + parameter.first.support.manager + " " + System.identityHashCode(this);