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