1 package org.simantics.pythonlink.variable;
\r
3 import java.util.ArrayList;
\r
4 import java.util.Arrays;
\r
5 import java.util.Collection;
\r
6 import java.util.Collections;
\r
7 import java.util.HashMap;
\r
8 import java.util.HashSet;
\r
9 import java.util.List;
\r
10 import java.util.Map;
\r
11 import java.util.Set;
\r
12 import java.util.regex.Matcher;
\r
13 import java.util.regex.Pattern;
\r
15 import org.simantics.databoard.Bindings;
\r
16 import org.simantics.databoard.Datatypes;
\r
17 import org.simantics.databoard.adapter.AdaptException;
\r
18 import org.simantics.databoard.binding.Binding;
\r
19 import org.simantics.databoard.binding.error.BindingException;
\r
20 import org.simantics.databoard.binding.mutable.Variant;
\r
21 import org.simantics.databoard.type.Datatype;
\r
22 import org.simantics.databoard.type.MapType;
\r
23 import org.simantics.databoard.type.RecordType;
\r
24 import org.simantics.pythonlink.NDArray;
\r
25 import org.simantics.pythonlink.PythonContext;
\r
26 import org.simantics.pythonlink.PythonContext.Listener;
\r
27 import org.simantics.pythonlink.PythonContext.VariableType;
\r
28 import org.simantics.simulator.variable.Realm;
\r
29 import org.simantics.simulator.variable.exceptions.NodeManagerException;
\r
30 import org.simantics.simulator.variable.impl.AbstractNodeManager;
\r
32 public class PythonNodeManager extends AbstractNodeManager<PythonNode> {
\r
33 PythonContext context;
\r
35 static Realm realm = new Realm() {
\r
36 public void asyncExec(Runnable runnable) {
\r
40 public void syncExec(Runnable runnable) {
\r
45 Map<String, Set<Runnable>> listeners = new HashMap<>();
\r
46 Map<String, PythonNode> nodes = new HashMap<>();
\r
48 PythonNode root = new PythonNode("/");
\r
50 static Pattern namePattern = Pattern.compile("/?([a-zA-Z_][a-zA-Z_0-9]*)");
\r
52 static MapType dictionaryType = new MapType(Datatypes.VARIANT, Datatypes.VARIANT);
\r
53 static RecordType ndarrayType = (RecordType)Bindings.getBindingUnchecked(NDArray.class).type();
\r
55 public PythonNodeManager(PythonContext context) {
\r
57 this.context = context;
\r
59 context.addListener(new Listener() {
\r
61 public void updated(String variableName) {
\r
62 if (variableName != null) {
\r
63 Set<Runnable> lis = listeners.get(variableName);
\r
65 for (Runnable r : lis)
\r
68 lis = listeners.get("/");
\r
70 for (Runnable r : lis)
\r
75 Set<Runnable> allRunnables = new HashSet<>();
\r
76 for (Collection<Runnable> s : listeners.values())
\r
77 allRunnables.addAll(s);
\r
78 for (Runnable r : allRunnables)
\r
84 public void closed() {
\r
86 Set<Runnable> allRunnables = new HashSet<>();
\r
87 for (Collection<Runnable> s : listeners.values())
\r
88 allRunnables.addAll(s);
\r
89 for (Runnable r : allRunnables)
\r
96 public Realm getRealm() {
\r
101 public String getName(PythonNode node) {
\r
102 return node.getName();
\r
106 public void addNodeListener(PythonNode node, Runnable listener) {
\r
107 synchronized(listeners) {
\r
108 if (!listeners.containsKey(node.getName())) listeners.put(node.getName(), new HashSet<>());
\r
109 listeners.get(node.getName()).add(listener);
\r
114 public void removeNodeListener(PythonNode node, Runnable listener) {
\r
115 synchronized(listeners) {
\r
116 if (!listeners.containsKey(node.getName()))
\r
117 listeners.get(node.getName()).remove(listener);
\r
122 public PythonNode getNode(String path) throws NodeManagerException {
\r
123 if (!context.isOpen())
\r
126 if ("/".equals(path))
\r
129 Matcher match = namePattern.matcher(path);
\r
130 if (!match.matches())
\r
133 String name = match.group(1);
\r
135 if (nodes.containsKey(name))
\r
136 return nodes.get(name);
\r
138 VariableType type = context.getPythonVariableType(name);
\r
139 if (type == VariableType.NO_VARIABLE)
\r
142 PythonNode node = new PythonNode(name);
\r
143 nodes.put(path, node);
\r
149 public PythonNode getChild(PythonNode node, String name) throws NodeManagerException {
\r
154 public PythonNode getProperty(PythonNode node, String name) throws NodeManagerException {
\r
155 if (node != root || !context.isOpen()) return null;
\r
157 return getNode(name);
\r
161 public List<String> getChildNames(PythonNode node) throws NodeManagerException {
\r
162 return Collections.emptyList();
\r
166 public List<PythonNode> getChildren(PythonNode node) throws NodeManagerException {
\r
167 return Collections.emptyList();
\r
171 public List<String> getPropertyNames(PythonNode node) throws NodeManagerException {
\r
172 if (node != root || !context.isOpen()) return Collections.emptyList();
\r
173 return Arrays.asList(context.getPythonVariableNames());
\r
177 public List<PythonNode> getProperties(PythonNode node) throws NodeManagerException {
\r
178 if (node != root || !context.isOpen()) return Collections.emptyList();
\r
180 String[] names = context.getPythonVariableNames();
\r
181 List<PythonNode> result = new ArrayList<>(names.length);
\r
183 for (String name : names) {
\r
184 result.add(getNode(name));
\r
191 public Datatype getDatatype(PythonNode node) throws NodeManagerException {
\r
192 String name = node.getName();
\r
195 type = context.getPythonVariableType(name);
\r
196 } catch (RuntimeException e) {
\r
197 throw new NodeManagerException("Failed to get type of variable " + name, e);
\r
201 case NO_VARIABLE: return Datatypes.VOID;
\r
202 case BOOLEAN: return Datatypes.BOOLEAN;
\r
203 case LONG: return Datatypes.LONG;
\r
204 case FLOAT: return Datatypes.DOUBLE;
\r
205 case STRING: return Datatypes.STRING;
\r
206 case BYTEARRAY: return Datatypes.BYTE_ARRAY;
\r
207 case DICTIONARY: return dictionaryType;
\r
208 case NDARRAY: return ndarrayType;
\r
209 case SEQUENCE: return Datatypes.VARIANT_ARRAY;
\r
210 case UNKNOWN: return Datatypes.VOID;
\r
211 default: throw new RuntimeException("Unknown python variable type");
\r
216 public Variant getValue(PythonNode node, String propertyName) throws NodeManagerException {
\r
217 if (node == root && context.isOpen())
\r
218 return context.getPythonVariantVariable(propertyName);
\r
220 throw new NodeManagerException("No value available for " + node.getName() + "#" + propertyName);
\r
224 public Object getValue(PythonNode node, String propertyName, Binding binding)
\r
225 throws NodeManagerException, BindingException {
\r
226 Variant value = getValue(node, propertyName);
\r
229 return value.getValue(binding);
\r
230 } catch (AdaptException e) {
\r
231 throw new BindingException(e);
\r
236 public Variant getValue(PythonNode node) throws NodeManagerException {
\r
237 if (node == root || !context.isOpen())
\r
238 throw new NodeManagerException("No value available for " + node.getName());
\r
240 String name = node.getName();
\r
243 return context.getPythonVariantVariable(name);
\r
244 } catch (RuntimeException e) {
\r
245 throw new NodeManagerException("Failed to get value of variable " + name, e);
\r
250 public Object getValue(PythonNode node, Binding binding) throws NodeManagerException, BindingException {
\r
251 Variant value = getValue(node);
\r
254 return value.getValue(binding);
\r
255 } catch (AdaptException e) {
\r
256 throw new BindingException(e);
\r
261 public void setValue(PythonNode node, String propertyName, Object value, Binding binding)
\r
262 throws NodeManagerException, BindingException {
\r
263 if (node != root || !context.isOpen()) throw new NodeManagerException("No property " + node.getName() + "#" + propertyName);
\r
265 context.setPythonVariantVariable(propertyName, value, binding);
\r
269 public void setValue(PythonNode node, Object value, Binding binding) throws NodeManagerException, BindingException {
\r
270 if (node == root || !context.isOpen()) throw new NodeManagerException("No property " + node.getName());
\r
271 String name = node.getName();
\r
273 context.setPythonVariantVariable(name, value, binding);
\r
277 public Set<String> getClassifications(PythonNode node) throws NodeManagerException {
\r
278 return Collections.emptySet();
\r