]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeValueRequest.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / variable / NodeValueRequest.java
diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeValueRequest.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeValueRequest.java
new file mode 100644 (file)
index 0000000..dcc5a6f
--- /dev/null
@@ -0,0 +1,233 @@
+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