]> gerrit.simantics Code Review - simantics/python.git/blob - org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java
Print exception type name if we can't get a traceback.
[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
17 public class PythonContext implements Closeable {
18     private long contextID;
19     
20     public interface Listener {
21         void updated(String variableName);
22         void closed();
23     }
24     
25     static ExecutorService pythonExecutor = Executors.newSingleThreadExecutor();
26     
27     Set<Listener> listeners = new HashSet<>();
28     
29     public enum VariableType {
30         NO_VARIABLE,
31         BOOLEAN,
32         LONG,
33         FLOAT,
34         STRING,
35         BYTEARRAY,
36         DICTIONARY,
37         NDARRAY,
38         SEQUENCE,
39         UNKNOWN
40     }
41     
42     static Pattern namePattern = Pattern.compile("([a-zA-Z_][a-zA-Z_0-9]*)");
43     
44     PythonContext() {
45         contextID = execute(() -> createContextImpl());
46     }
47     
48     public void addListener(Listener listener) {
49         listeners.add(listener);
50     }
51     
52     public void removeListener(Listener listener) {
53                 listeners.remove(listener);
54     }
55     
56     @Override
57     public void close() {
58         long id = contextID;
59         contextID = 0;
60         if (id != 0) execute(() -> deleteContextImpl(id));
61         
62         for (Listener l : listeners) {
63                 l.closed();
64         }
65     }
66
67         public boolean isOpen() {
68                 return contextID != 0;
69         }
70         
71     @Override
72     protected void finalize() throws Throwable {
73         super.finalize();
74         close();
75     }
76     
77     public void executePythonStatement(String statement) {
78         execute(() -> executePythonStatementImpl( contextID, statement ));
79         for (Listener l : listeners) { l.updated(null); }
80     }
81
82     // Setters
83     
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); }
88     }
89
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); }
94     }
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); }
99     }
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); }
104     }
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); }
109     }
110     
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); }
115     }
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); }
120     }
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); }
125     }
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); }
130     }
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); }
135     }
136
137     // Getters
138     
139     public boolean getPythonBooleanVariable(String variableName) {
140         checkValidName(variableName);
141         return getPythonBooleanVariableImpl(contextID, variableName);
142     }
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");
148         return (int) value;
149     }
150     public long getPythonLongVariable(String variableName) {
151         checkValidName(variableName);
152         return execute(() -> getPythonLongVariableImpl(contextID, variableName));
153     }
154     public double getPythonDoubleVariable(String variableName) {
155         checkValidName(variableName);
156         return execute(() -> getPythonDoubleVariableImpl(contextID, variableName));
157     }
158     public String getPythonStringVariable(String variableName) {
159         checkValidName(variableName);
160         return execute(() -> getPythonStringVariableImpl(contextID, variableName));
161     }
162     
163     public boolean[] getPythonBooleanArrayVariable(String variableName) {
164         checkValidName(variableName);
165         return execute(() -> getPythonBooleanArrayVariableImpl(contextID, variableName));
166     }
167     public int[] getPythonIntegerArrayVariable(String variableName) {
168         checkValidName(variableName);
169         return execute(() -> getPythonIntegerArrayVariableImpl(contextID, variableName));
170     }
171     public long[] getPythonLongArrayVariable(String variableName) {
172         checkValidName(variableName);
173         return execute(() -> getPythonLongArrayVariableImpl(contextID, variableName));
174     }
175     public double[] getPythonDoubleArrayVariable(String variableName) {
176         checkValidName(variableName);
177         return execute(() -> getPythonDoubleArrayVariableImpl(contextID, variableName));
178     }
179     public String[] getPythonStringArrayVariable(String variableName) {
180         checkValidName(variableName);
181         return execute(() -> getPythonStringArrayVariableImpl(contextID, variableName));
182     }
183     
184     public void setPythonNDArrayVariable(String variableName, NDArray value) {
185         checkValidName(variableName);
186         execute(() -> setPythonNDArrayVariableImpl(contextID, variableName, value));
187     }
188     public NDArray getPythonNDArrayVariable(String variableName) {
189         checkValidName(variableName);
190         return execute(() -> getPythonNDArrayVariableImpl(contextID, variableName));
191     }
192
193     public Object getPythonVariantVariable(String variableName, Binding binding) {
194         checkValidName(variableName);
195         Object result = execute(() -> getPythonVariantVariableImpl(contextID, variableName));
196         try {
197                         return Bindings.OBJECT.getContent(result, binding);
198                 } catch (BindingException e) {
199                         throw new RuntimeException(e);
200                 }
201     }
202     
203     public Variant getPythonVariantVariable(String variableName) {
204         checkValidName(variableName);
205         return Variant.ofInstance(execute(() -> getPythonVariantVariableImpl(contextID, variableName)));
206     }
207
208     public void setPythonVariantVariable(String variableName, Variant value) {
209         setPythonVariantVariable(variableName, value.getValue(), value.getBinding());
210     }
211     
212     public void setPythonVariantVariable(String variableName, Object value, Binding binding) {
213         checkValidName(variableName);
214         if (!binding.isInstance(value)) throw new IllegalArgumentException("Invalid object binding");
215         
216         execute(() -> setPythonVariantVariableImpl(contextID, variableName, value, binding));
217         
218         for (Listener l : listeners) { l.updated(variableName); }
219     }
220     
221     public VariableType getPythonVariableType(String variableName) {
222         checkValidName(variableName);
223         int code = execute(() -> getPythonVariableTypeImpl(contextID, variableName));
224         
225         VariableType[] values = VariableType.values();
226         if (code < 0 || code >= values.length)
227                 return VariableType.UNKNOWN;
228         
229         return values[code];
230     }
231     
232     public String[] getPythonVariableNames() {
233         return execute(() -> getPythonVariableNamesImpl(contextID));
234     }
235      
236     private static void checkValidName(String variableName) {
237         if (!namePattern.matcher(variableName).matches())
238             throw new IllegalArgumentException("Invalid Python variable name " + variableName);
239     }
240     
241     static void execute(Runnable job) {
242         try {
243             pythonExecutor.submit(job).get();
244         } catch (InterruptedException | ExecutionException e) {
245             throw new RuntimeException(e);
246         }
247     }
248     
249     static <V> V execute(Callable<V> job) {
250         try {
251             return pythonExecutor.submit(job).get();
252         } catch (InterruptedException | ExecutionException e) {
253             throw new RuntimeException(e);
254         }
255     }
256     
257     // Native function declarations
258     private static native long createContextImpl();
259     private static native void deleteContextImpl(long contextID);
260     
261     private static native int executePythonStatementImpl(long contextID, String statement);
262     
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);
267     
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);
273     
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);
278     
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);
284     
285     private static native void setPythonNDArrayVariableImpl(long contextID, String variableName, NDArray value);
286     private static native NDArray getPythonNDArrayVariableImpl(long contextID, String variableName);
287     
288     private static native void setPythonVariantVariableImpl(long contextID, String variableName, Object value, Binding binding);
289     private static native Object getPythonVariantVariableImpl(long contextID, String variableName);
290     
291     private static native int getPythonVariableTypeImpl(long contextID, String variableName);
292     
293     private static native String[] getPythonVariableNamesImpl(long contextID);
294 }