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.common.utils.Logger;
10 import org.simantics.db.exception.DatabaseException;
11 import org.simantics.db.procedure.Listener;
12 import org.simantics.simulator.variable.exceptions.NodeIsNotValidAnymoreException;
13 import org.simantics.simulator.variable.exceptions.NodeManagerException;
14 import org.simantics.utils.datastructures.Pair;
16 @SuppressWarnings("rawtypes")
17 class NodeValueRequest extends ParametrizedPrimitiveRead<Pair<VariableNode,Binding>, Variant> implements VariableNodeReadRunnable {
19 private Listener<Variant> listener = null;
20 private Variant value = Variables.PENDING_NODE_VALUE;
21 private boolean wasRun = false;
23 static class Probe implements Runnable {
25 private Pair<VariableNode,Binding> parameter;
26 public Variant result;
28 public Probe(Pair<VariableNode,Binding> parameter) {
29 this.parameter = parameter;
32 @SuppressWarnings("unchecked")
36 result = NodeValueRequest.get(parameter);
37 parameter.first.support.valueCache.put(parameter.first.node, result, 1000000000L);
38 } catch (NodeManagerException e) {
40 } catch (BindingException e) {
47 public NodeValueRequest(VariableNode node) {
48 super(Pair.<VariableNode, Binding>make(node, null));
51 public NodeValueRequest(VariableNode node, Binding binding) {
52 super(Pair.<VariableNode, Binding>make(node, binding));
55 @SuppressWarnings("unchecked")
57 public void register(ReadGraph graph, final Listener<Variant> procedure) {
59 VariableNode node = parameter.first;
61 if(procedure.isDisposed()) {
63 // We are not listening
64 Variant result = (Variant)node.support.valueCache.get(node.node);
67 // Return cached value immediately
68 procedure.execute(result);
72 // listener = procedure;
74 // if(graph.getSynchronous()) {
76 // parameter.support.manager.getRealm().syncExec(this);
77 // } catch (InterruptedException e) {
78 // if (!wasRun) procedure.exception(e);
79 // } catch (Throwable e) {
80 // if (!wasRun) procedure.exception(e);
83 // parameter.support.manager.getRealm().asyncExec(this);
85 // if(value == Variables.PENDING_NODE_VALUE) {
86 // procedure.execute(Variables.PENDING_NODE_VALUE);
91 NodeValueRequest.Probe probe = new Probe(parameter);
92 node.support.manager.getRealm().asyncExec(probe);
93 if(probe.result != null) {
94 procedure.execute(probe.result);
96 procedure.execute(Variables.PENDING_NODE_VALUE);
105 listener = procedure;
106 // Register listening
107 node.support.manager.addNodeListener(node.node, this);
110 procedure.execute(value);
112 Variant result = (Variant)node.support.valueCache.get(node.node);
114 procedure.execute(result);
116 procedure.execute(Variables.PENDING_NODE_VALUE);
121 // if(listener != null) {
122 // throw new UnsupportedOperationException();
124 // listener = procedure;
125 // if(graph.getSynchronous()) {
127 // parameter.support.manager.getRealm().syncExec(new VariableNodeReadRunnable() {
129 // public void run() {
130 // parameter.support.manager.addNodeListener(parameter.node, NodeValueRequest.this);
133 // public String toString() {
134 // return "NodeValueRequest.register.sync.addNodeListener @ " + System.identityHashCode(NodeValueRequest.this);
138 // if (!wasRun) procedure.exception(new InternalException("No invocation of listener from node manager " + parameter.support.manager.getClass().getName()));
139 // } catch (InterruptedException e) {
140 // if (!wasRun) procedure.exception(e);
141 // } catch (Throwable e) {
142 // if (!wasRun) procedure.exception(e);
145 // parameter.support.manager.addNodeListener(parameter.node, this);
146 // if(value == Variables.PENDING_NODE_VALUE) procedure.execute(Variables.PENDING_NODE_VALUE);
151 static class NodeListener implements VariableNodeReadRunnable {
153 private VariableNode node;
154 private NodeValueRequest request;
156 public NodeListener(VariableNode node, NodeValueRequest request) {
158 this.request = request;
161 @SuppressWarnings("unchecked")
164 node.support.manager.addNodeListener(node.node, request);
170 @SuppressWarnings("unchecked")
172 public void unregistered() {
173 VariableNode node = parameter.first;
174 node.support.manager.removeNodeListener(node.node, this);
175 node.support.valueCache.removeListening(node.node);
179 @SuppressWarnings("unchecked")
180 public static Variant get(Pair<VariableNode,Binding> parameter) throws NodeManagerException, BindingException {
182 VariableNode node = parameter.first;
183 Binding binding = parameter.second;
185 if (binding != null) {
186 Object raw = node.support.manager.getValue(node.node, binding);
187 if(raw == null) return null;
188 else return new Variant(binding, raw);
190 return node.support.manager.getValue(node.node);
195 @SuppressWarnings("unchecked")
197 public synchronized void run() {
199 VariableNode node = parameter.first;
202 Variant newValue = get(parameter);
203 if (wasRun && ObjectUtils.objectEquals(value, newValue)) {
204 //System.out.println("CACHE VALUE MATCH (" + newValue + ") for " + node.node);
208 node.support.valueCache.put(node.node, value);
209 } catch (Throwable e) {
210 // Must catch everything to prevent DB client from getting stuck.
211 if(!(e instanceof NodeIsNotValidAnymoreException))
212 Logger.defaultLogError(e);
213 // Invoke the exception method of the listener
214 Listener<Variant> listener = this.listener;
215 if (listener != null) listener.exception(new DatabaseException("External data access error", e));
219 // Must always invoke an existing listener, regardless of earlier errors.
220 Listener<Variant> listener = this.listener;
221 if (listener != null) {
222 //System.out.println("LISTENER " + listener + " invoked with value " + value);
223 listener.execute(value);
229 public String toString() {
230 return "NodeValueRequest.run " + parameter.first.node + " " + parameter.first.support.manager + " " + System.identityHashCode(this);