--- /dev/null
+package org.simantics.db.layer0.variable;\r
+\r
+import java.util.Collections;\r
+import java.util.List;\r
+import java.util.Map;\r
+\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.layer0.variable.Variables.NodeStructure;\r
+import org.simantics.db.procedure.Listener;\r
+import org.simantics.simulator.variable.exceptions.NodeManagerException;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+@SuppressWarnings("rawtypes")\r
+class NodeStructureRequest extends ParametrizedPrimitiveRead<VariableNode, NodeStructure> implements VariableNodeReadRunnable {\r
+\r
+ private Listener<NodeStructure> listener = null;\r
+ private NodeStructure value = Variables.PENDING_NODE_STRUCTURE;\r
+ private boolean wasRun = false;\r
+\r
+ static class Probe implements Runnable {\r
+\r
+ private VariableNode node;\r
+ public NodeStructure result;\r
+\r
+ public Probe(VariableNode node) {\r
+ this.node = node;\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public void run() {\r
+ try {\r
+ result = NodeStructureRequest.get(node);\r
+ node.support.structureCache.put(node.node, result, 1000000000L);\r
+ } catch (NodeManagerException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ public NodeStructureRequest(VariableNode node) {\r
+ super(node);\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public void register(ReadGraph graph, final Listener<NodeStructure> procedure) {\r
+\r
+ if(procedure.isDisposed()) {\r
+\r
+ // We are not listening\r
+ NodeStructure result = (NodeStructure)parameter.support.structureCache.get(parameter.node);\r
+\r
+ if(result != null) {\r
+ // Return cached value immediately\r
+ procedure.execute(result);\r
+ } else {\r
+ NodeStructureRequest.Probe probe = new Probe(parameter);\r
+ parameter.support.manager.getRealm().asyncExec(probe);\r
+ if(probe.result != null) {\r
+ procedure.execute(probe.result);\r
+ } else {\r
+ procedure.execute(Variables.PENDING_NODE_STRUCTURE);\r
+ }\r
+ }\r
+\r
+ return;\r
+\r
+ }\r
+\r
+ // We need to listen\r
+ listener = procedure;\r
+ // Register listening\r
+ parameter.support.manager.addNodeListener(parameter.node, this);\r
+ synchronized(this) {\r
+ if(wasRun) {\r
+ procedure.execute(value);\r
+ } else {\r
+ NodeStructure result = (NodeStructure)parameter.support.structureCache.get(parameter.node);\r
+ if(result != null) {\r
+ procedure.execute(result);\r
+ } else {\r
+ procedure.execute(Variables.PENDING_NODE_STRUCTURE);\r
+ }\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ static class NodeListener implements VariableNodeReadRunnable {\r
+\r
+ private VariableNode node;\r
+ private NodeStructureRequest request;\r
+\r
+ public NodeListener(VariableNode node, NodeStructureRequest 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
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public void unregistered() {\r
+ parameter.support.manager.removeNodeListener(parameter.node, this);\r
+ parameter.support.structureCache.removeListening(parameter.node);\r
+ listener = null;\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+ public static NodeStructure get(VariableNode parameter) throws NodeManagerException {\r
+ List<?> children = parameter.support.manager.getChildren(parameter.node);\r
+ List<?> properties = parameter.support.manager.getProperties(parameter.node);\r
+ Map<String, Object> childMap = Collections.emptyMap();\r
+ Map<String, Object> propertyMap = childMap;\r
+ if(!children.isEmpty()) {\r
+ childMap = new THashMap<>(children.size());\r
+ for(Object o : children) {\r
+ String name = parameter.support.manager.getName(o);\r
+ childMap.put(name, o);\r
+ }\r
+ }\r
+ if(!properties.isEmpty()) {\r
+ propertyMap = new THashMap<>(properties.size());\r
+ for(Object o : properties) {\r
+ String name = parameter.support.manager.getName(o);\r
+ propertyMap.put(name, o);\r
+ }\r
+ }\r
+ return new NodeStructure(childMap, propertyMap);\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public synchronized void run() {\r
+ try {\r
+ // Cache this value with infinite cache time since we are listening\r
+ NodeStructure 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
+ parameter.support.structureCache.put(parameter.node, value);\r
+ } catch (Throwable e) {\r
+ // Must catch everything to prevent DB client from getting stuck.\r
+ Logger.defaultLogError(e);\r
+ // Invoke the exception method of the listener\r
+ Listener<NodeStructure> listener = this.listener;\r
+ if (listener != null) listener.exception(new DatabaseException("External data access error", e));\r
+ wasRun = true;\r
+ return;\r
+ }\r
+\r
+ // Must always invoke an existing listener, regardless of earlier errors.\r
+ Listener<NodeStructure> listener = this.listener;\r
+ if (listener != null) {\r
+ listener.execute(value);\r
+ }\r
+ wasRun = true;\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ return "NodeStructureRequest.run @ " + System.identityHashCode(this);\r
+ }\r
+\r
+}
\ No newline at end of file