1 package org.simantics.db.layer0.variable;
\r
3 import java.util.Collections;
\r
4 import java.util.List;
\r
5 import java.util.Map;
\r
7 import org.simantics.databoard.util.ObjectUtils;
\r
8 import org.simantics.db.ReadGraph;
\r
9 import org.simantics.db.common.request.ParametrizedPrimitiveRead;
\r
10 import org.simantics.db.common.utils.Logger;
\r
11 import org.simantics.db.exception.DatabaseException;
\r
12 import org.simantics.db.layer0.variable.Variables.NodeStructure;
\r
13 import org.simantics.db.procedure.Listener;
\r
14 import org.simantics.simulator.variable.exceptions.NodeManagerException;
\r
16 import gnu.trove.map.hash.THashMap;
\r
18 @SuppressWarnings("rawtypes")
\r
19 class NodeStructureRequest extends ParametrizedPrimitiveRead<VariableNode, NodeStructure> implements VariableNodeReadRunnable {
\r
21 private Listener<NodeStructure> listener = null;
\r
22 private NodeStructure value = Variables.PENDING_NODE_STRUCTURE;
\r
23 private boolean wasRun = false;
\r
25 static class Probe implements Runnable {
\r
27 private VariableNode node;
\r
28 public NodeStructure result;
\r
30 public Probe(VariableNode node) {
\r
34 @SuppressWarnings("unchecked")
\r
38 result = NodeStructureRequest.get(node);
\r
39 node.support.structureCache.put(node.node, result, 1000000000L);
\r
40 } catch (NodeManagerException e) {
\r
41 e.printStackTrace();
\r
47 public NodeStructureRequest(VariableNode node) {
\r
51 @SuppressWarnings("unchecked")
\r
53 public void register(ReadGraph graph, final Listener<NodeStructure> procedure) {
\r
55 if(procedure.isDisposed()) {
\r
57 // We are not listening
\r
58 NodeStructure result = (NodeStructure)parameter.support.structureCache.get(parameter.node);
\r
60 if(result != null) {
\r
61 // Return cached value immediately
\r
62 procedure.execute(result);
\r
64 NodeStructureRequest.Probe probe = new Probe(parameter);
\r
65 parameter.support.manager.getRealm().asyncExec(probe);
\r
66 if(probe.result != null) {
\r
67 procedure.execute(probe.result);
\r
69 procedure.execute(Variables.PENDING_NODE_STRUCTURE);
\r
77 // We need to listen
\r
78 listener = procedure;
\r
79 // Register listening
\r
80 parameter.support.manager.addNodeListener(parameter.node, this);
\r
81 synchronized(this) {
\r
83 procedure.execute(value);
\r
85 NodeStructure result = (NodeStructure)parameter.support.structureCache.get(parameter.node);
\r
86 if(result != null) {
\r
87 procedure.execute(result);
\r
89 procedure.execute(Variables.PENDING_NODE_STRUCTURE);
\r
96 static class NodeListener implements VariableNodeReadRunnable {
\r
98 private VariableNode node;
\r
99 private NodeStructureRequest request;
\r
101 public NodeListener(VariableNode node, NodeStructureRequest request) {
\r
103 this.request = request;
\r
106 @SuppressWarnings("unchecked")
\r
108 public void run() {
\r
109 node.support.manager.addNodeListener(node.node, request);
\r
114 @SuppressWarnings("unchecked")
\r
116 public void unregistered() {
\r
117 parameter.support.manager.removeNodeListener(parameter.node, this);
\r
118 parameter.support.structureCache.removeListening(parameter.node);
\r
122 @SuppressWarnings("unchecked")
\r
123 public static NodeStructure get(VariableNode parameter) throws NodeManagerException {
\r
124 List<?> children = parameter.support.manager.getChildren(parameter.node);
\r
125 List<?> properties = parameter.support.manager.getProperties(parameter.node);
\r
126 Map<String, Object> childMap = Collections.emptyMap();
\r
127 Map<String, Object> propertyMap = childMap;
\r
128 if(!children.isEmpty()) {
\r
129 childMap = new THashMap<>(children.size());
\r
130 for(Object o : children) {
\r
131 String name = parameter.support.manager.getName(o);
\r
132 childMap.put(name, o);
\r
135 if(!properties.isEmpty()) {
\r
136 propertyMap = new THashMap<>(properties.size());
\r
137 for(Object o : properties) {
\r
138 String name = parameter.support.manager.getName(o);
\r
139 propertyMap.put(name, o);
\r
142 return new NodeStructure(childMap, propertyMap);
\r
145 @SuppressWarnings("unchecked")
\r
147 public synchronized void run() {
\r
149 // Cache this value with infinite cache time since we are listening
\r
150 NodeStructure newValue = get(parameter);
\r
151 if (wasRun && ObjectUtils.objectEquals(value, newValue)) {
\r
152 //System.out.println("CACHE VALUE MATCH (" + newValue + ") for " + node.node);
\r
156 parameter.support.structureCache.put(parameter.node, value);
\r
157 } catch (Throwable e) {
\r
158 // Must catch everything to prevent DB client from getting stuck.
\r
159 Logger.defaultLogError(e);
\r
160 // Invoke the exception method of the listener
\r
161 Listener<NodeStructure> listener = this.listener;
\r
162 if (listener != null) listener.exception(new DatabaseException("External data access error", e));
\r
167 // Must always invoke an existing listener, regardless of earlier errors.
\r
168 Listener<NodeStructure> listener = this.listener;
\r
169 if (listener != null) {
\r
170 listener.execute(value);
\r
176 public String toString() {
\r
177 return "NodeStructureRequest.run @ " + System.identityHashCode(this);
\r