--- /dev/null
+package org.simantics.db.layer0.variable;\r
+\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
+import org.simantics.databoard.util.ObjectUtils;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.common.request.ParametrizedPrimitiveRead;\r
+import org.simantics.db.common.utils.Logger;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.procedure.Listener;\r
+import org.simantics.simulator.variable.exceptions.NodeIsNotValidAnymoreException;\r
+import org.simantics.simulator.variable.exceptions.NodeManagerException;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+@SuppressWarnings("rawtypes")\r
+class NodeValueRequest extends ParametrizedPrimitiveRead<Pair<VariableNode,Binding>, Variant> implements VariableNodeReadRunnable {\r
+\r
+ private Listener<Variant> listener = null;\r
+ private Variant value = Variables.PENDING_NODE_VALUE;\r
+ private boolean wasRun = false;\r
+\r
+ static class Probe implements Runnable {\r
+\r
+ private Pair<VariableNode,Binding> parameter;\r
+ public Variant result;\r
+ \r
+ public Probe(Pair<VariableNode,Binding> parameter) {\r
+ this.parameter = parameter;\r
+ }\r
+ \r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public void run() {\r
+ try {\r
+ result = NodeValueRequest.get(parameter);\r
+ parameter.first.support.valueCache.put(parameter.first.node, result, 1000000000L);\r
+ } catch (NodeManagerException e) {\r
+ e.printStackTrace();\r
+ } catch (BindingException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ \r
+ }\r
+ \r
+ public NodeValueRequest(VariableNode node) {\r
+ super(Pair.<VariableNode, Binding>make(node, null));\r
+ }\r
+\r
+ public NodeValueRequest(VariableNode node, Binding binding) {\r
+ super(Pair.<VariableNode, Binding>make(node, binding));\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public void register(ReadGraph graph, final Listener<Variant> procedure) {\r
+ \r
+ VariableNode node = parameter.first;\r
+\r
+ if(procedure.isDisposed()) {\r
+ \r
+ // We are not listening\r
+ Variant result = (Variant)node.support.valueCache.get(node.node);\r
+\r
+ if(result != null) {\r
+ // Return cached value immediately\r
+ procedure.execute(result);\r
+ } else {\r
+\r
+// \r
+// listener = procedure;\r
+// \r
+// if(graph.getSynchronous()) {\r
+// try {\r
+// parameter.support.manager.getRealm().syncExec(this);\r
+// } catch (InterruptedException e) {\r
+// if (!wasRun) procedure.exception(e);\r
+// } catch (Throwable e) {\r
+// if (!wasRun) procedure.exception(e);\r
+// }\r
+// } else {\r
+// parameter.support.manager.getRealm().asyncExec(this);\r
+// \r
+// if(value == Variables.PENDING_NODE_VALUE) {\r
+// procedure.execute(Variables.PENDING_NODE_VALUE);\r
+// }\r
+// }\r
+// return;\r
+ \r
+ NodeValueRequest.Probe probe = new Probe(parameter);\r
+ node.support.manager.getRealm().asyncExec(probe);\r
+ if(probe.result != null) {\r
+ procedure.execute(probe.result);\r
+ } else {\r
+ procedure.execute(Variables.PENDING_NODE_VALUE);\r
+ }\r
+\r
+ }\r
+\r
+ return; \r
+ }\r
+ \r
+ // We need to listen\r
+ listener = procedure;\r
+ // Register listening\r
+ node.support.manager.addNodeListener(node.node, this);\r
+ synchronized(this) {\r
+ if(wasRun) {\r
+ procedure.execute(value);\r
+ } else {\r
+ Variant result = (Variant)node.support.valueCache.get(node.node);\r
+ if(result != null) {\r
+ procedure.execute(result);\r
+ } else {\r
+ procedure.execute(Variables.PENDING_NODE_VALUE);\r
+ }\r
+ }\r
+ }\r
+ \r
+// if(listener != null) {\r
+// throw new UnsupportedOperationException();\r
+// }\r
+// listener = procedure;\r
+// if(graph.getSynchronous()) {\r
+// try {\r
+// parameter.support.manager.getRealm().syncExec(new VariableNodeReadRunnable() {\r
+// @Override\r
+// public void run() {\r
+// parameter.support.manager.addNodeListener(parameter.node, NodeValueRequest.this);\r
+// }\r
+// @Override\r
+// public String toString() {\r
+// return "NodeValueRequest.register.sync.addNodeListener @ " + System.identityHashCode(NodeValueRequest.this);\r
+// }\r
+// });\r
+// \r
+// if (!wasRun) procedure.exception(new InternalException("No invocation of listener from node manager " + parameter.support.manager.getClass().getName()));\r
+// } catch (InterruptedException e) {\r
+// if (!wasRun) procedure.exception(e);\r
+// } catch (Throwable e) {\r
+// if (!wasRun) procedure.exception(e);\r
+// }\r
+// } else {\r
+// parameter.support.manager.addNodeListener(parameter.node, this);\r
+// if(value == Variables.PENDING_NODE_VALUE) procedure.execute(Variables.PENDING_NODE_VALUE);\r
+// }\r
+ \r
+ }\r
+ \r
+ static class NodeListener implements VariableNodeReadRunnable {\r
+ \r
+ private VariableNode node;\r
+ private NodeValueRequest request;\r
+ \r
+ public NodeListener(VariableNode node, NodeValueRequest request) {\r
+ this.node = node;\r
+ this.request = request;\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public void run() {\r
+ node.support.manager.addNodeListener(node.node, request);\r
+ }\r
+ \r
+ }\r
+\r
+\r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public void unregistered() {\r
+ VariableNode node = parameter.first;\r
+ node.support.manager.removeNodeListener(node.node, this);\r
+ node.support.valueCache.removeListening(node.node);\r
+ listener = null;\r
+ }\r
+ \r
+ @SuppressWarnings("unchecked")\r
+ public static Variant get(Pair<VariableNode,Binding> parameter) throws NodeManagerException, BindingException {\r
+\r
+ VariableNode node = parameter.first;\r
+ Binding binding = parameter.second;\r
+ \r
+ if (binding != null) {\r
+ Object raw = node.support.manager.getValue(node.node, binding);\r
+ if(raw == null) return null;\r
+ else return new Variant(binding, raw);\r
+ } else {\r
+ return node.support.manager.getValue(node.node);\r
+ }\r
+ \r
+ }\r
+ \r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public synchronized void run() {\r
+ \r
+ VariableNode node = parameter.first;\r
+ \r
+ try {\r
+ Variant newValue = get(parameter);\r
+ if (wasRun && ObjectUtils.objectEquals(value, newValue)) {\r
+ //System.out.println("CACHE VALUE MATCH (" + newValue + ") for " + node.node);\r
+ return;\r
+ }\r
+ value = newValue;\r
+ node.support.valueCache.put(node.node, value);\r
+ } catch (Throwable e) {\r
+ // Must catch everything to prevent DB client from getting stuck.\r
+ if(!(e instanceof NodeIsNotValidAnymoreException))\r
+ Logger.defaultLogError(e);\r
+ // Invoke the exception method of the listener\r
+ Listener<Variant> listener = this.listener;\r
+ if (listener != null) listener.exception(new DatabaseException("External data access error", e));\r
+ wasRun = true;\r
+ return;\r
+ }\r
+ // Must always invoke an existing listener, regardless of earlier errors.\r
+ Listener<Variant> listener = this.listener;\r
+ if (listener != null) {\r
+ //System.out.println("LISTENER " + listener + " invoked with value " + value);\r
+ listener.execute(value);\r
+ }\r
+ wasRun = true;\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ return "NodeValueRequest.run " + parameter.first.node + " " + parameter.first.support.manager + " " + System.identityHashCode(this);\r
+ }\r
+\r
+}
\ No newline at end of file