]> gerrit.simantics Code Review - simantics/python.git/blob - org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java
16b02348196b4326f70f4475173a94677928c433
[simantics/python.git] / org.simantics.pythonlink / src / org / simantics / pythonlink / PythonContext.java
1 package org.simantics.pythonlink;
2
3 import java.io.Closeable;
4 import java.util.HashSet;
5 import java.util.Set;
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;
11
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;
18
19 public class PythonContext implements Closeable {
20     private long contextID;
21     
22     public interface Listener {
23         void updated(String variableName);
24         void closed();
25     }
26     
27     static ExecutorService pythonExecutor = Executors.newSingleThreadExecutor();
28     
29     Set<Listener> listeners = new HashSet<>();
30     
31     public enum VariableType {
32         NO_VARIABLE,
33         BOOLEAN,
34         LONG,
35         FLOAT,
36         STRING,
37         BYTEARRAY,
38         DICTIONARY,
39         NDARRAY,
40         SEQUENCE,
41         UNKNOWN
42     }
43     
44     static Pattern namePattern = Pattern.compile("([a-zA-Z_][a-zA-Z_0-9]*)");
45     
46     PythonContext() {
47         contextID = execute(() -> createContextImpl());
48     }
49     
50     public void addListener(Listener listener) {
51         listeners.add(listener);
52     }
53     
54     public void removeListener(Listener listener) {
55                 listeners.remove(listener);
56     }
57     
58     @Override
59     public void close() {
60         long id = contextID;
61         contextID = 0;
62         if (id != 0) execute(() -> deleteContextImpl(id));
63         
64         for (Listener l : listeners) {
65                 l.closed();
66         }
67     }
68
69         public boolean isOpen() {
70                 return contextID != 0;
71         }
72         
73     @Override
74     protected void finalize() throws Throwable {
75         super.finalize();
76         close();
77     }
78     
79     public void executePythonStatement(String statement) {
80         SCLContext sclContext = SCLContext.getCurrent();
81         
82         execute(() -> {
83                 SCLContext.push(sclContext);
84                 executePythonStatementImpl( contextID, statement );
85                 SCLContext.pop();
86         });
87         
88         for (Listener l : listeners) { l.updated(null); }
89     }
90
91     // Setters
92     
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); }
97     }
98
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); }
103     }
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); }
108     }
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); }
113     }
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); }
118     }
119     
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); }
124     }
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); }
129     }
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); }
134     }
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); }
139     }
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); }
144     }
145
146     // Getters
147     
148     public boolean getPythonBooleanVariable(String variableName) {
149         checkValidName(variableName);
150         return getPythonBooleanVariableImpl(contextID, variableName);
151     }
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");
157         return (int) value;
158     }
159     public long getPythonLongVariable(String variableName) {
160         checkValidName(variableName);
161         return execute(() -> getPythonLongVariableImpl(contextID, variableName));
162     }
163     public double getPythonDoubleVariable(String variableName) {
164         checkValidName(variableName);
165         return execute(() -> getPythonDoubleVariableImpl(contextID, variableName));
166     }
167     public String getPythonStringVariable(String variableName) {
168         checkValidName(variableName);
169         return execute(() -> getPythonStringVariableImpl(contextID, variableName));
170     }
171     
172     public boolean[] getPythonBooleanArrayVariable(String variableName) {
173         checkValidName(variableName);
174         return execute(() -> getPythonBooleanArrayVariableImpl(contextID, variableName));
175     }
176     public int[] getPythonIntegerArrayVariable(String variableName) {
177         checkValidName(variableName);
178         return execute(() -> getPythonIntegerArrayVariableImpl(contextID, variableName));
179     }
180     public long[] getPythonLongArrayVariable(String variableName) {
181         checkValidName(variableName);
182         return execute(() -> getPythonLongArrayVariableImpl(contextID, variableName));
183     }
184     public double[] getPythonDoubleArrayVariable(String variableName) {
185         checkValidName(variableName);
186         return execute(() -> getPythonDoubleArrayVariableImpl(contextID, variableName));
187     }
188     public String[] getPythonStringArrayVariable(String variableName) {
189         checkValidName(variableName);
190         return execute(() -> getPythonStringArrayVariableImpl(contextID, variableName));
191     }
192     
193     public void setPythonNDArrayVariable(String variableName, NDArray value) {
194         checkValidName(variableName);
195         execute(() -> setPythonNDArrayVariableImpl(contextID, variableName, value));
196     }
197     public NDArray getPythonNDArrayVariable(String variableName) {
198         checkValidName(variableName);
199         return execute(() -> getPythonNDArrayVariableImpl(contextID, variableName));
200     }
201
202     public Object getPythonVariantVariable(String variableName, Binding binding) {
203         checkValidName(variableName);
204         Object result = execute(() -> getPythonVariantVariableImpl(contextID, variableName));
205         try {
206                         return Bindings.OBJECT.getContent(result, binding);
207                 } catch (BindingException e) {
208                         throw new RuntimeException(e);
209                 }
210     }
211     
212     public Variant getPythonVariantVariable(String variableName) {
213         checkValidName(variableName);
214         return Variant.ofInstance(execute(() -> getPythonVariantVariableImpl(contextID, variableName)));
215     }
216
217     public void setPythonVariantVariable(String variableName, Variant value) {
218         setPythonVariantVariable(variableName, value.getValue(), value.getBinding());
219     }
220     
221     public void setPythonVariantVariable(String variableName, Object value, Binding binding) {
222         checkValidName(variableName);
223         if (!binding.isInstance(value)) throw new IllegalArgumentException("Invalid object binding");
224         
225         execute(() -> setPythonVariantVariableImpl(contextID, variableName, value, binding));
226         
227         for (Listener l : listeners) { l.updated(variableName); }
228     }
229     
230     public VariableType getPythonVariableType(String variableName) {
231         checkValidName(variableName);
232         int code = execute(() -> getPythonVariableTypeImpl(contextID, variableName));
233         
234         VariableType[] values = VariableType.values();
235         if (code < 0 || code >= values.length)
236                 return VariableType.UNKNOWN;
237         
238         return values[code];
239     }
240     
241     public String[] getPythonVariableNames() {
242         return execute(() -> getPythonVariableNamesImpl(contextID));
243     }
244      
245     private static void checkValidName(String variableName) {
246         if (!namePattern.matcher(variableName).matches())
247             throw new IllegalArgumentException("Invalid Python variable name " + variableName);
248     }
249     
250     static void execute(Runnable job) {
251         try {
252             pythonExecutor.submit(job).get();
253         } catch (InterruptedException | ExecutionException e) {
254             throw new RuntimeException(e);
255         }
256     }
257     
258     static <V> V execute(Callable<V> job) {
259         try {
260             return pythonExecutor.submit(job).get();
261         } catch (InterruptedException | ExecutionException e) {
262             throw new RuntimeException(e);
263         }
264     }
265     
266     // Native function declarations
267     private static native long createContextImpl();
268     private static native void deleteContextImpl(long contextID);
269     
270     private static native int executePythonStatementImpl(long contextID, String statement);
271     
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);
276     
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);
282     
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);
287     
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);
293     
294     private static native void setPythonNDArrayVariableImpl(long contextID, String variableName, NDArray value);
295     private static native NDArray getPythonNDArrayVariableImpl(long contextID, String variableName);
296     
297     private static native void setPythonVariantVariableImpl(long contextID, String variableName, Object value, Binding binding);
298     private static native Object getPythonVariantVariableImpl(long contextID, String variableName);
299     
300     private static native int getPythonVariableTypeImpl(long contextID, String variableName);
301     
302     private static native String[] getPythonVariableNamesImpl(long contextID);
303 }