]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeValueRequest.java
Merge commit 'ad8333027322fda6b9a8a524c7a7e15a54c52f38'
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / variable / NodeValueRequest.java
1 package org.simantics.db.layer0.variable;\r
2 \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
15 \r
16 @SuppressWarnings("rawtypes")\r
17 class NodeValueRequest extends ParametrizedPrimitiveRead<Pair<VariableNode,Binding>, Variant> implements VariableNodeReadRunnable {\r
18 \r
19     private Listener<Variant> listener = null;\r
20     private Variant value = Variables.PENDING_NODE_VALUE;\r
21     private boolean wasRun = false;\r
22 \r
23     static class Probe implements Runnable {\r
24 \r
25         private Pair<VariableNode,Binding> parameter;\r
26                 public Variant result;\r
27         \r
28         public Probe(Pair<VariableNode,Binding> parameter) {\r
29                 this.parameter = parameter;\r
30         }\r
31         \r
32                 @SuppressWarnings("unchecked")\r
33                 @Override\r
34                 public void run() {\r
35                         try {\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
42                         }\r
43                 }\r
44         \r
45     }\r
46     \r
47     public NodeValueRequest(VariableNode node) {\r
48         super(Pair.<VariableNode, Binding>make(node, null));\r
49     }\r
50 \r
51     public NodeValueRequest(VariableNode node, Binding binding) {\r
52         super(Pair.<VariableNode, Binding>make(node, binding));\r
53     }\r
54 \r
55     @SuppressWarnings("unchecked")\r
56     @Override\r
57     public void register(ReadGraph graph, final Listener<Variant> procedure) {\r
58         \r
59         VariableNode node = parameter.first;\r
60 \r
61         if(procedure.isDisposed()) {\r
62                 \r
63                 // We are not listening\r
64                 Variant result = (Variant)node.support.valueCache.get(node.node);\r
65 \r
66                 if(result != null) {\r
67                         // Return cached value immediately\r
68                         procedure.execute(result);\r
69                 } else {\r
70 \r
71 //              \r
72 //            listener = procedure;\r
73 //            \r
74 //            if(graph.getSynchronous()) {\r
75 //                try {\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
81 //                }\r
82 //            } else {\r
83 //                parameter.support.manager.getRealm().asyncExec(this);\r
84 //            \r
85 //                if(value == Variables.PENDING_NODE_VALUE) {\r
86 //                    procedure.execute(Variables.PENDING_NODE_VALUE);\r
87 //                }\r
88 //            }\r
89 //            return;\r
90             \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
95                         } else {\r
96                                 procedure.execute(Variables.PENDING_NODE_VALUE);\r
97                         }\r
98 \r
99                 }\r
100 \r
101                 return;            \r
102         }\r
103         \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
109                         if(wasRun) {\r
110                                 procedure.execute(value);\r
111                         } else {\r
112                                 Variant result = (Variant)node.support.valueCache.get(node.node);\r
113                                 if(result != null) {\r
114                                         procedure.execute(result);\r
115                                 } else {\r
116                         procedure.execute(Variables.PENDING_NODE_VALUE);\r
117                                 }\r
118                         }\r
119                 }\r
120         \r
121 //        if(listener != null) {\r
122 //            throw new UnsupportedOperationException();\r
123 //        }\r
124 //        listener = procedure;\r
125 //        if(graph.getSynchronous()) {\r
126 //            try {\r
127 //                parameter.support.manager.getRealm().syncExec(new VariableNodeReadRunnable() {\r
128 //                    @Override\r
129 //                    public void run() {\r
130 //                        parameter.support.manager.addNodeListener(parameter.node, NodeValueRequest.this);\r
131 //                    }\r
132 //                    @Override\r
133 //                    public String toString() {\r
134 //                        return "NodeValueRequest.register.sync.addNodeListener @ " + System.identityHashCode(NodeValueRequest.this);\r
135 //                    }\r
136 //                });\r
137 //                \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
143 //            }\r
144 //        } else {\r
145 //            parameter.support.manager.addNodeListener(parameter.node, this);\r
146 //            if(value == Variables.PENDING_NODE_VALUE) procedure.execute(Variables.PENDING_NODE_VALUE);\r
147 //        }\r
148                 \r
149     }\r
150     \r
151     static class NodeListener implements VariableNodeReadRunnable {\r
152         \r
153         private VariableNode node;\r
154         private NodeValueRequest request;\r
155         \r
156         public NodeListener(VariableNode node, NodeValueRequest request) {\r
157                 this.node = node;\r
158                 this.request = request;\r
159         }\r
160 \r
161         @SuppressWarnings("unchecked")\r
162         @Override\r
163         public void run() {\r
164             node.support.manager.addNodeListener(node.node, request);\r
165         }\r
166         \r
167     }\r
168 \r
169 \r
170     @SuppressWarnings("unchecked")\r
171     @Override\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
176         listener = null;\r
177     }\r
178     \r
179     @SuppressWarnings("unchecked")\r
180     public static Variant get(Pair<VariableNode,Binding> parameter) throws NodeManagerException, BindingException {\r
181 \r
182         VariableNode node = parameter.first;\r
183         Binding binding = parameter.second;\r
184         \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
189         } else {\r
190                 return node.support.manager.getValue(node.node);\r
191         }\r
192         \r
193     }\r
194     \r
195     @SuppressWarnings("unchecked")\r
196     @Override\r
197     public synchronized void run() {\r
198         \r
199         VariableNode node = parameter.first;\r
200         \r
201         try {\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
205                 return;\r
206             }\r
207             value = newValue;\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
216             wasRun = true;\r
217             return;\r
218         }\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
224         }\r
225         wasRun = true;\r
226     }\r
227 \r
228     @Override\r
229     public String toString() {\r
230         return "NodeValueRequest.run " + parameter.first.node + " " + parameter.first.support.manager + " " + System.identityHashCode(this);\r
231     }\r
232 \r
233 }