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