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