1 package org.simantics.pythonlink;
\r
3 import java.io.Closeable;
\r
4 import java.util.HashSet;
\r
5 import java.util.Set;
\r
6 import java.util.concurrent.Callable;
\r
7 import java.util.concurrent.ExecutionException;
\r
8 import java.util.concurrent.ExecutorService;
\r
9 import java.util.concurrent.Executors;
\r
10 import java.util.regex.Pattern;
\r
12 import org.simantics.databoard.Bindings;
\r
13 import org.simantics.databoard.binding.Binding;
\r
14 import org.simantics.databoard.binding.error.BindingException;
\r
15 import org.simantics.databoard.binding.mutable.Variant;
\r
17 public class PythonContext implements Closeable {
\r
18 private long contextID;
\r
20 public interface Listener {
\r
21 void updated(String variableName);
\r
25 static ExecutorService pythonExecutor = Executors.newSingleThreadExecutor();
\r
27 Set<Listener> listeners = new HashSet<>();
\r
29 public enum VariableType {
\r
42 static Pattern namePattern = Pattern.compile("([a-zA-Z_][a-zA-Z_0-9]*)");
\r
45 contextID = createContextImpl();
\r
48 public void addListener(Listener listener) {
\r
49 listeners.add(listener);
\r
52 public void removeListener(Listener listener) {
\r
53 listeners.remove(listener);
\r
57 public void close() {
\r
58 long id = contextID;
\r
60 if (id != 0) deleteContextImpl(id);
\r
62 for (Listener l : listeners) {
\r
67 public boolean isOpen() {
\r
68 return contextID != 0;
\r
72 protected void finalize() throws Throwable {
\r
77 public void executePythonStatement(String statement) {
\r
78 execute(() -> executePythonStatementImpl( contextID, statement ));
\r
79 for (Listener l : listeners) { l.updated(null); }
\r
84 public void setPythonBooleanVariable(String variableName, boolean value) {
\r
85 checkValidName(variableName);
\r
86 execute(() -> setPythonBooleanVariableImpl(contextID, variableName, value));
\r
87 for (Listener l : listeners) { l.updated(variableName); }
\r
90 public void setPythonIntegerVariable(String variableName, int value) {
\r
91 checkValidName(variableName);
\r
92 execute(() -> setPythonLongVariableImpl(contextID, variableName, value));
\r
93 for (Listener l : listeners) { l.updated(variableName); }
\r
95 public void setPythonLongVariable(String variableName, long value) {
\r
96 checkValidName(variableName);
\r
97 execute(() -> setPythonLongVariableImpl(contextID, variableName, value));
\r
98 for (Listener l : listeners) { l.updated(variableName); }
\r
100 public void setPythonDoubleVariable(String variableName, double value) {
\r
101 checkValidName(variableName);
\r
102 execute(() -> setPythonDoubleVariableImpl(contextID, variableName, value));
\r
103 for (Listener l : listeners) { l.updated(variableName); }
\r
105 public void setPythonStringVariable(String variableName, String value) {
\r
106 checkValidName(variableName);
\r
107 execute(() -> setPythonStringVariableImpl(contextID, variableName, value));
\r
108 for (Listener l : listeners) { l.updated(variableName); }
\r
111 public void setPythonBooleanArrayVariable(String variableName, boolean[] value) {
\r
112 checkValidName(variableName);
\r
113 execute(() -> setPythonBooleanArrayVariableImpl(contextID, variableName, value));
\r
114 for (Listener l : listeners) { l.updated(variableName); }
\r
116 public void setPythonIntegerArrayVariable(String variableName, int[] value) {
\r
117 checkValidName(variableName);
\r
118 execute(() -> setPythonIntegerArrayVariableImpl(contextID, variableName, value));
\r
119 for (Listener l : listeners) { l.updated(variableName); }
\r
121 public void setPythonLongArrayVariable(String variableName, long[] value) {
\r
122 checkValidName(variableName);
\r
123 execute(() -> setPythonLongArrayVariableImpl(contextID, variableName, value));
\r
124 for (Listener l : listeners) { l.updated(variableName); }
\r
126 public void setPythonDoubleArrayVariable(String variableName, double[] value) {
\r
127 checkValidName(variableName);
\r
128 execute(() -> setPythonDoubleArrayVariableImpl(contextID, variableName, value));
\r
129 for (Listener l : listeners) { l.updated(variableName); }
\r
131 public void setPythonStringArrayVariable(String variableName, String[] value) {
\r
132 checkValidName(variableName);
\r
133 execute(() -> setPythonStringArrayVariableImpl(contextID, variableName, value));
\r
134 for (Listener l : listeners) { l.updated(variableName); }
\r
139 public boolean getPythonBooleanVariable(String variableName) {
\r
140 checkValidName(variableName);
\r
141 return getPythonBooleanVariableImpl(contextID, variableName);
\r
143 public int getPythonIntegerVariable(String variableName) {
\r
144 checkValidName(variableName);
\r
145 long value = execute(() -> getPythonLongVariableImpl(contextID, variableName));
\r
146 if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE)
\r
147 throw new RuntimeException("Python value not in integer range");
\r
148 return (int) value;
\r
150 public long getPythonLongVariable(String variableName) {
\r
151 checkValidName(variableName);
\r
152 return execute(() -> getPythonLongVariableImpl(contextID, variableName));
\r
154 public double getPythonDoubleVariable(String variableName) {
\r
155 checkValidName(variableName);
\r
156 return execute(() -> getPythonDoubleVariableImpl(contextID, variableName));
\r
158 public String getPythonStringVariable(String variableName) {
\r
159 checkValidName(variableName);
\r
160 return execute(() -> getPythonStringVariableImpl(contextID, variableName));
\r
163 public boolean[] getPythonBooleanArrayVariable(String variableName) {
\r
164 checkValidName(variableName);
\r
165 return execute(() -> getPythonBooleanArrayVariableImpl(contextID, variableName));
\r
167 public int[] getPythonIntegerArrayVariable(String variableName) {
\r
168 checkValidName(variableName);
\r
169 return execute(() -> getPythonIntegerArrayVariableImpl(contextID, variableName));
\r
171 public long[] getPythonLongArrayVariable(String variableName) {
\r
172 checkValidName(variableName);
\r
173 return execute(() -> getPythonLongArrayVariableImpl(contextID, variableName));
\r
175 public double[] getPythonDoubleArrayVariable(String variableName) {
\r
176 checkValidName(variableName);
\r
177 return execute(() -> getPythonDoubleArrayVariableImpl(contextID, variableName));
\r
179 public String[] getPythonStringArrayVariable(String variableName) {
\r
180 checkValidName(variableName);
\r
181 return execute(() -> getPythonStringArrayVariableImpl(contextID, variableName));
\r
184 public void setPythonNDArrayVariable(String variableName, NDArray value) {
\r
185 checkValidName(variableName);
\r
186 execute(() -> setPythonNDArrayVariableImpl(contextID, variableName, value));
\r
188 public NDArray getPythonNDArrayVariable(String variableName) {
\r
189 checkValidName(variableName);
\r
190 return execute(() -> getPythonNDArrayVariableImpl(contextID, variableName));
\r
193 public Object getPythonVariantVariable(String variableName, Binding binding) {
\r
194 checkValidName(variableName);
\r
195 Object result = execute(() -> getPythonVariantVariableImpl(contextID, variableName));
\r
197 return Bindings.OBJECT.getContent(result, binding);
\r
198 } catch (BindingException e) {
\r
199 throw new RuntimeException(e);
\r
203 public Variant getPythonVariantVariable(String variableName) {
\r
204 checkValidName(variableName);
\r
205 return Variant.ofInstance(execute(() -> getPythonVariantVariableImpl(contextID, variableName)));
\r
208 public void setPythonVariantVariable(String variableName, Variant value) {
\r
209 setPythonVariantVariable(variableName, value.getValue(), value.getBinding());
\r
212 public void setPythonVariantVariable(String variableName, Object value, Binding binding) {
\r
213 checkValidName(variableName);
\r
214 if (!binding.isInstance(value)) throw new IllegalArgumentException("Invalid object binding");
\r
216 execute(() -> setPythonVariantVariableImpl(contextID, variableName, value, binding));
\r
218 for (Listener l : listeners) { l.updated(variableName); }
\r
221 public VariableType getPythonVariableType(String variableName) {
\r
222 checkValidName(variableName);
\r
223 int code = execute(() -> getPythonVariableTypeImpl(contextID, variableName));
\r
225 VariableType[] values = VariableType.values();
\r
226 if (code < 0 || code >= values.length)
\r
227 return VariableType.UNKNOWN;
\r
229 return values[code];
\r
232 public String[] getPythonVariableNames() {
\r
233 return execute(() -> getPythonVariableNamesImpl(contextID));
\r
236 private static void checkValidName(String variableName) {
\r
237 if (!namePattern.matcher(variableName).matches())
\r
238 throw new IllegalArgumentException("Invalid Python variable name " + variableName);
\r
241 static void execute(Runnable job) {
\r
243 pythonExecutor.submit(job).get();
\r
244 } catch (InterruptedException | ExecutionException e) {
\r
245 throw new RuntimeException(e);
\r
249 static <V> V execute(Callable<V> job) {
\r
251 return pythonExecutor.submit(job).get();
\r
252 } catch (InterruptedException | ExecutionException e) {
\r
253 throw new RuntimeException(e);
\r
257 // Native function declarations
\r
258 private static native long createContextImpl();
\r
259 private static native void deleteContextImpl(long contextID);
\r
261 private static native int executePythonStatementImpl(long contextID, String statement);
\r
263 private static native void setPythonBooleanVariableImpl(long contextID, String variableName, boolean value);
\r
264 private static native void setPythonLongVariableImpl(long contextID, String variableName, long value);
\r
265 private static native void setPythonDoubleVariableImpl(long contextID, String variableName, double value);
\r
266 private static native void setPythonStringVariableImpl(long contextID, String variableName, String value);
\r
268 private static native void setPythonBooleanArrayVariableImpl(long contextID, String variableName, boolean[] value);
\r
269 private static native void setPythonIntegerArrayVariableImpl(long contextID, String variableName, int[] value);
\r
270 private static native void setPythonLongArrayVariableImpl(long contextID, String variableName, long[] value);
\r
271 private static native void setPythonDoubleArrayVariableImpl(long contextID, String variableName, double[] value);
\r
272 private static native void setPythonStringArrayVariableImpl(long contextID, String variableName, String[] value);
\r
274 private static native boolean getPythonBooleanVariableImpl(long contextID, String variableName);
\r
275 private static native long getPythonLongVariableImpl(long contextID, String variableName);
\r
276 private static native double getPythonDoubleVariableImpl(long contextID, String variableName);
\r
277 private static native String getPythonStringVariableImpl(long contextID, String variableName);
\r
279 private static native boolean[] getPythonBooleanArrayVariableImpl(long contextID, String variableName);
\r
280 private static native long[] getPythonLongArrayVariableImpl(long contextID, String variableName);
\r
281 private static native int[] getPythonIntegerArrayVariableImpl(long contextID, String variableName);
\r
282 private static native double[] getPythonDoubleArrayVariableImpl(long contextID, String variableName);
\r
283 private static native String[] getPythonStringArrayVariableImpl(long contextID, String variableName);
\r
285 private static native void setPythonNDArrayVariableImpl(long contextID, String variableName, NDArray value);
\r
286 private static native NDArray getPythonNDArrayVariableImpl(long contextID, String variableName);
\r
288 private static native void setPythonVariantVariableImpl(long contextID, String variableName, Object value, Binding binding);
\r
289 private static native Object getPythonVariantVariableImpl(long contextID, String variableName);
\r
291 private static native int getPythonVariableTypeImpl(long contextID, String variableName);
\r
293 private static native String[] getPythonVariableNamesImpl(long contextID);
\r