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;
16 import org.simantics.scl.runtime.SCLContext;
17 import org.simantics.scl.runtime.reporting.SCLReportingHandler;
19 public class PythonContext implements Closeable {
20 private long contextID;
22 public interface Listener {
23 void updated(String variableName);
27 static ExecutorService pythonExecutor = Executors.newSingleThreadExecutor();
29 Set<Listener> listeners = new HashSet<>();
31 public enum VariableType {
44 static Pattern namePattern = Pattern.compile("([a-zA-Z_][a-zA-Z_0-9]*)");
47 contextID = execute(() -> createContextImpl());
50 public void addListener(Listener listener) {
51 listeners.add(listener);
54 public void removeListener(Listener listener) {
55 listeners.remove(listener);
62 if (id != 0) execute(() -> deleteContextImpl(id));
64 for (Listener l : listeners) {
69 public boolean isOpen() {
70 return contextID != 0;
74 protected void finalize() throws Throwable {
79 public void executePythonStatement(String statement) {
80 SCLContext sclContext = SCLContext.getCurrent();
83 SCLContext.push(sclContext);
84 executePythonStatementImpl( contextID, statement );
88 for (Listener l : listeners) { l.updated(null); }
93 public void setPythonBooleanVariable(String variableName, boolean value) {
94 checkValidName(variableName);
95 execute(() -> setPythonBooleanVariableImpl(contextID, variableName, value));
96 for (Listener l : listeners) { l.updated(variableName); }
99 public void setPythonIntegerVariable(String variableName, int value) {
100 checkValidName(variableName);
101 execute(() -> setPythonLongVariableImpl(contextID, variableName, value));
102 for (Listener l : listeners) { l.updated(variableName); }
104 public void setPythonLongVariable(String variableName, long value) {
105 checkValidName(variableName);
106 execute(() -> setPythonLongVariableImpl(contextID, variableName, value));
107 for (Listener l : listeners) { l.updated(variableName); }
109 public void setPythonDoubleVariable(String variableName, double value) {
110 checkValidName(variableName);
111 execute(() -> setPythonDoubleVariableImpl(contextID, variableName, value));
112 for (Listener l : listeners) { l.updated(variableName); }
114 public void setPythonStringVariable(String variableName, String value) {
115 checkValidName(variableName);
116 execute(() -> setPythonStringVariableImpl(contextID, variableName, value));
117 for (Listener l : listeners) { l.updated(variableName); }
120 public void setPythonBooleanArrayVariable(String variableName, boolean[] value) {
121 checkValidName(variableName);
122 execute(() -> setPythonBooleanArrayVariableImpl(contextID, variableName, value));
123 for (Listener l : listeners) { l.updated(variableName); }
125 public void setPythonIntegerArrayVariable(String variableName, int[] value) {
126 checkValidName(variableName);
127 execute(() -> setPythonIntegerArrayVariableImpl(contextID, variableName, value));
128 for (Listener l : listeners) { l.updated(variableName); }
130 public void setPythonLongArrayVariable(String variableName, long[] value) {
131 checkValidName(variableName);
132 execute(() -> setPythonLongArrayVariableImpl(contextID, variableName, value));
133 for (Listener l : listeners) { l.updated(variableName); }
135 public void setPythonDoubleArrayVariable(String variableName, double[] value) {
136 checkValidName(variableName);
137 execute(() -> setPythonDoubleArrayVariableImpl(contextID, variableName, value));
138 for (Listener l : listeners) { l.updated(variableName); }
140 public void setPythonStringArrayVariable(String variableName, String[] value) {
141 checkValidName(variableName);
142 execute(() -> setPythonStringArrayVariableImpl(contextID, variableName, value));
143 for (Listener l : listeners) { l.updated(variableName); }
148 public boolean getPythonBooleanVariable(String variableName) {
149 checkValidName(variableName);
150 return getPythonBooleanVariableImpl(contextID, variableName);
152 public int getPythonIntegerVariable(String variableName) {
153 checkValidName(variableName);
154 long value = execute(() -> getPythonLongVariableImpl(contextID, variableName));
155 if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE)
156 throw new RuntimeException("Python value not in integer range");
159 public long getPythonLongVariable(String variableName) {
160 checkValidName(variableName);
161 return execute(() -> getPythonLongVariableImpl(contextID, variableName));
163 public double getPythonDoubleVariable(String variableName) {
164 checkValidName(variableName);
165 return execute(() -> getPythonDoubleVariableImpl(contextID, variableName));
167 public String getPythonStringVariable(String variableName) {
168 checkValidName(variableName);
169 return execute(() -> getPythonStringVariableImpl(contextID, variableName));
172 public boolean[] getPythonBooleanArrayVariable(String variableName) {
173 checkValidName(variableName);
174 return execute(() -> getPythonBooleanArrayVariableImpl(contextID, variableName));
176 public int[] getPythonIntegerArrayVariable(String variableName) {
177 checkValidName(variableName);
178 return execute(() -> getPythonIntegerArrayVariableImpl(contextID, variableName));
180 public long[] getPythonLongArrayVariable(String variableName) {
181 checkValidName(variableName);
182 return execute(() -> getPythonLongArrayVariableImpl(contextID, variableName));
184 public double[] getPythonDoubleArrayVariable(String variableName) {
185 checkValidName(variableName);
186 return execute(() -> getPythonDoubleArrayVariableImpl(contextID, variableName));
188 public String[] getPythonStringArrayVariable(String variableName) {
189 checkValidName(variableName);
190 return execute(() -> getPythonStringArrayVariableImpl(contextID, variableName));
193 public void setPythonNDArrayVariable(String variableName, NDArray value) {
194 checkValidName(variableName);
195 execute(() -> setPythonNDArrayVariableImpl(contextID, variableName, value));
197 public NDArray getPythonNDArrayVariable(String variableName) {
198 checkValidName(variableName);
199 return execute(() -> getPythonNDArrayVariableImpl(contextID, variableName));
202 public Object getPythonVariantVariable(String variableName, Binding binding) {
203 checkValidName(variableName);
204 Object result = execute(() -> getPythonVariantVariableImpl(contextID, variableName));
206 return Bindings.OBJECT.getContent(result, binding);
207 } catch (BindingException e) {
208 throw new RuntimeException(e);
212 public Variant getPythonVariantVariable(String variableName) {
213 checkValidName(variableName);
214 return Variant.ofInstance(execute(() -> getPythonVariantVariableImpl(contextID, variableName)));
217 public void setPythonVariantVariable(String variableName, Variant value) {
218 setPythonVariantVariable(variableName, value.getValue(), value.getBinding());
221 public void setPythonVariantVariable(String variableName, Object value, Binding binding) {
222 checkValidName(variableName);
223 if (!binding.isInstance(value)) throw new IllegalArgumentException("Invalid object binding");
225 execute(() -> setPythonVariantVariableImpl(contextID, variableName, value, binding));
227 for (Listener l : listeners) { l.updated(variableName); }
230 public VariableType getPythonVariableType(String variableName) {
231 checkValidName(variableName);
232 int code = execute(() -> getPythonVariableTypeImpl(contextID, variableName));
234 VariableType[] values = VariableType.values();
235 if (code < 0 || code >= values.length)
236 return VariableType.UNKNOWN;
241 public String[] getPythonVariableNames() {
242 return execute(() -> getPythonVariableNamesImpl(contextID));
245 private static void checkValidName(String variableName) {
246 if (!namePattern.matcher(variableName).matches())
247 throw new IllegalArgumentException("Invalid Python variable name " + variableName);
250 static void execute(Runnable job) {
252 pythonExecutor.submit(job).get();
253 } catch (InterruptedException | ExecutionException e) {
254 throw new RuntimeException(e);
258 static <V> V execute(Callable<V> job) {
260 return pythonExecutor.submit(job).get();
261 } catch (InterruptedException | ExecutionException e) {
262 throw new RuntimeException(e);
266 // Native function declarations
267 private static native long createContextImpl();
268 private static native void deleteContextImpl(long contextID);
270 private static native int executePythonStatementImpl(long contextID, String statement);
272 private static native void setPythonBooleanVariableImpl(long contextID, String variableName, boolean value);
273 private static native void setPythonLongVariableImpl(long contextID, String variableName, long value);
274 private static native void setPythonDoubleVariableImpl(long contextID, String variableName, double value);
275 private static native void setPythonStringVariableImpl(long contextID, String variableName, String value);
277 private static native void setPythonBooleanArrayVariableImpl(long contextID, String variableName, boolean[] value);
278 private static native void setPythonIntegerArrayVariableImpl(long contextID, String variableName, int[] value);
279 private static native void setPythonLongArrayVariableImpl(long contextID, String variableName, long[] value);
280 private static native void setPythonDoubleArrayVariableImpl(long contextID, String variableName, double[] value);
281 private static native void setPythonStringArrayVariableImpl(long contextID, String variableName, String[] value);
283 private static native boolean getPythonBooleanVariableImpl(long contextID, String variableName);
284 private static native long getPythonLongVariableImpl(long contextID, String variableName);
285 private static native double getPythonDoubleVariableImpl(long contextID, String variableName);
286 private static native String getPythonStringVariableImpl(long contextID, String variableName);
288 private static native boolean[] getPythonBooleanArrayVariableImpl(long contextID, String variableName);
289 private static native long[] getPythonLongArrayVariableImpl(long contextID, String variableName);
290 private static native int[] getPythonIntegerArrayVariableImpl(long contextID, String variableName);
291 private static native double[] getPythonDoubleArrayVariableImpl(long contextID, String variableName);
292 private static native String[] getPythonStringArrayVariableImpl(long contextID, String variableName);
294 private static native void setPythonNDArrayVariableImpl(long contextID, String variableName, NDArray value);
295 private static native NDArray getPythonNDArrayVariableImpl(long contextID, String variableName);
297 private static native void setPythonVariantVariableImpl(long contextID, String variableName, Object value, Binding binding);
298 private static native Object getPythonVariantVariableImpl(long contextID, String variableName);
300 private static native int getPythonVariableTypeImpl(long contextID, String variableName);
302 private static native String[] getPythonVariableNamesImpl(long contextID);