]> gerrit.simantics Code Review - simantics/python.git/blob - org.simantics.pythonlink.win32.x86_64/src/sclpy.c
Get Python traceback output in the messages of exceptions from the pythonlink feature.
[simantics/python.git] / org.simantics.pythonlink.win32.x86_64 / src / sclpy.c
1 ///////////////////////////////////////////////////////\r
2 //                                                   //\r
3 //   VTT Technical Research Centre of Finland LTD    //\r
4 //   For internal use only. Do not redistribute.     //\r
5 //                                                   //\r
6 //   Authors:                                        //\r
7 //       Antton Tapani    ext-antton.tapani@vtt.fi   //\r
8 //                                                   //\r
9 //   Last modified by Antton Tapani    9.2016        //\r
10 //                                                   //\r
11 ///////////////////////////////////////////////////////\r
12 \r
13 #include "sclpy.h"\r
14 \r
15 #include <windows.h>\r
16 \r
17 jint throwException( JNIEnv *env, char *className, char *message )\r
18 {\r
19     jclass exClass = (*env)->FindClass( env, className);\r
20     if (exClass == NULL) {\r
21         return 0;\r
22     }\r
23 \r
24     return (*env)->ThrowNew( env, exClass, message );\r
25 }\r
26 \r
27 jint throwPythonException( JNIEnv *env, char *message ) {\r
28         return throwException( env, PYTHON_EXCEPTION, message );\r
29 }\r
30 \r
31 jint throwIllegalArgumentException( JNIEnv *env, char *message ) {\r
32         return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message );\r
33 }\r
34 \r
35 int moduleCount = 0;\r
36 int initCalled = 0;\r
37 int hasNumpy = 0;\r
38 \r
39 JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) {\r
40         char name[16];\r
41 \r
42         if (!initCalled) {\r
43         Py_Initialize();\r
44         initCalled = 1;\r
45 \r
46         hasNumpy = _import_array();\r
47         hasNumpy = hasNumpy != -1;\r
48         }\r
49 \r
50         sprintf(name, "SCL_%d", ++moduleCount);\r
51 \r
52         {\r
53                 PyObject *module = PyModule_New(name);\r
54                 PyObject *main = PyImport_AddModule("__main__");\r
55 \r
56                 PyDict_Merge(PyModule_GetDict(module), PyModule_GetDict(main), 0);\r
57 \r
58                 return (jlong)module;\r
59         }\r
60 }\r
61 \r
62 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) {\r
63         PyObject *module = (PyObject*)contextID;\r
64         Py_XDECREF(module);\r
65 }\r
66 \r
67 PyObject *getPythonBool(jboolean value) {\r
68         if (value) {\r
69                 Py_RETURN_TRUE;\r
70         }\r
71         else {\r
72                 Py_RETURN_FALSE;\r
73         }\r
74 }\r
75 \r
76 PyObject *getPythonString(JNIEnv *env, jstring string) {\r
77         jsize len = (*env)->GetStringLength(env, string);\r
78         const jchar *chars = (*env)->GetStringChars(env, string, NULL);\r
79 \r
80         PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);\r
81 \r
82         (*env)->ReleaseStringChars(env, string, chars);\r
83         return value;\r
84 }\r
85 \r
86 PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) {\r
87         jsize nitems = (*env)->GetArrayLength(env, value);\r
88         jint *values = (*env)->GetIntArrayElements(env, value, NULL);\r
89         jclass stringClass = (*env)->FindClass(env, STRING_CLASS);\r
90         jint i;\r
91 \r
92         PyObject *result = PyList_New(nitems);\r
93         for (i = 0; i < nitems; i++) {\r
94                 jobject item = (*env)->GetObjectArrayElement(env, value, i);\r
95                 if (item != NULL && (*env)->IsInstanceOf(env, item, stringClass)) {\r
96                         PyList_SetItem(result, i, getPythonString(env, (jstring)item));\r
97                 }\r
98                 else {\r
99                         PyList_SetItem(result, i, Py_None);\r
100                 }\r
101         }\r
102 \r
103         (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);\r
104         return result;\r
105 }\r
106 \r
107 PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) {\r
108         jsize nitems = (*env)->GetArrayLength(env, value);\r
109         jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL);\r
110         jint i;\r
111 \r
112         PyObject *result = PyList_New(nitems);\r
113         for (i = 0; i < nitems; i++) {\r
114                 PyList_SetItem(result, i, getPythonBool(values[i]));\r
115         }\r
116 \r
117         (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT);\r
118         return result;\r
119 }\r
120 \r
121 PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) {\r
122         jint len = (*env)->GetArrayLength(env, value);\r
123         jbyte *values = (*env)->GetByteArrayElements(env, value, NULL);\r
124 \r
125         PyObject *result = PyByteArray_FromStringAndSize(values, len);\r
126 \r
127         (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT);\r
128         return result;\r
129 }\r
130 \r
131 PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) {\r
132         jsize nitems = (*env)->GetArrayLength(env, value);\r
133         jint *values = (*env)->GetIntArrayElements(env, value, NULL);\r
134         jint i;\r
135 \r
136         PyObject *result = PyList_New(nitems);\r
137         for (i = 0; i < nitems; i++) {\r
138                 PyList_SetItem(result, i, PyLong_FromLong(values[i]));\r
139         }\r
140 \r
141         (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);\r
142         return result;\r
143 }\r
144 \r
145 PyObject *getPythonLongList(JNIEnv *env, jlongArray value) {\r
146         jsize nitems = (*env)->GetArrayLength(env, value);\r
147         jlong *values = (*env)->GetLongArrayElements(env, value, NULL);\r
148         jint i;\r
149 \r
150         PyObject *result = PyList_New(nitems);\r
151         for (i = 0; i < nitems; i++) {\r
152                 PyList_SetItem(result, i, PyLong_FromLongLong(values[i]));\r
153         }\r
154 \r
155         (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT);\r
156         return result;\r
157 }\r
158 \r
159 PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) {\r
160         jsize nitems = (*env)->GetArrayLength(env, value);\r
161         float *values = (*env)->GetFloatArrayElements(env, value, NULL);\r
162         jint i;\r
163 \r
164         PyObject *result = PyList_New(nitems);\r
165         for (i = 0; i < nitems; i++) {\r
166                 PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i]));\r
167         }\r
168 \r
169         (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT);\r
170         return result;\r
171 }\r
172 \r
173 PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) {\r
174         jsize nitems = (*env)->GetArrayLength(env, value);\r
175         double *values = (*env)->GetDoubleArrayElements(env, value, NULL);\r
176         jint i;\r
177 \r
178         PyObject *result = PyList_New(nitems);\r
179         for (i = 0; i < nitems; i++) {\r
180                 PyList_SetItem(result, i, PyFloat_FromDouble(values[i]));\r
181         }\r
182 \r
183         (*env)->ReleaseDoubleArrayElements(env, value, values, JNI_ABORT);\r
184         return result;\r
185 }\r
186 \r
187 PyObject *getPythonNDArray(JNIEnv *env, jobject value) {\r
188         jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);\r
189         jmethodID dimsMethod = (*env)->GetMethodID(env, ndarrayClass, "dims", "()[I");\r
190         jmethodID getValuesMethod = (*env)->GetMethodID(env, ndarrayClass, "getValues", "()[D");\r
191 \r
192         jintArray jdims = (*env)->CallObjectMethod(env, value, dimsMethod);\r
193         jsize ndims = (*env)->GetArrayLength(env, jdims);\r
194         jint *dims = (*env)->GetIntArrayElements(env, jdims, NULL);\r
195 \r
196         jdoubleArray jvalues = (*env)->CallObjectMethod(env, value, getValuesMethod);\r
197         jsize len = (*env)->GetArrayLength(env, jvalues);\r
198         jdouble *values = (*env)->GetDoubleArrayElements(env, jvalues, NULL);\r
199 \r
200         npy_intp *pyDims = (npy_intp*)malloc(ndims * sizeof(npy_intp));\r
201 \r
202         jint i, nelem = ndims > 0 ? 1 : 0;\r
203         for (i = 0; i < ndims; i++) {\r
204                 nelem *= dims[i];\r
205                 pyDims[i] = dims[i];\r
206         }\r
207 \r
208         len = min(len, nelem);\r
209 \r
210         {\r
211                 PyObject *array = PyArray_EMPTY(ndims, pyDims, NPY_DOUBLE, 0);\r
212                 double *data = (double *)PyArray_DATA((PyArrayObject*)array);\r
213 \r
214                 memcpy(data, values, len * sizeof(double));\r
215 \r
216                 free(pyDims);\r
217 \r
218                 (*env)->ReleaseDoubleArrayElements(env, jvalues, values, JNI_ABORT);\r
219                 (*env)->ReleaseIntArrayElements(env, jdims, dims, JNI_ABORT);\r
220 \r
221                 return array;\r
222         }\r
223 }\r
224 \r
225 PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) {\r
226         jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS);\r
227         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z");\r
228 \r
229         jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object);\r
230         return getPythonBool(bvalue);\r
231 }\r
232 \r
233 PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) {\r
234         jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS);\r
235         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B");\r
236 \r
237         jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object);\r
238         return PyLong_FromLong(v);\r
239 }\r
240 \r
241 PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) {\r
242         jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS);\r
243         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I");\r
244 \r
245         jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object);\r
246         return PyLong_FromLong(v);\r
247 }\r
248 \r
249 PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) {\r
250         jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS);\r
251         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J");\r
252 \r
253         jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object);\r
254         return PyLong_FromLongLong(v);\r
255 }\r
256 \r
257 PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) {\r
258         jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS);\r
259         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F");\r
260 \r
261         jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object);\r
262         return PyFloat_FromDouble(v);\r
263 }\r
264 \r
265 PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) {\r
266         jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS);\r
267         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D");\r
268 \r
269         jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object);\r
270         return PyFloat_FromDouble(v);\r
271 }\r
272 \r
273 PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) {\r
274         jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS);\r
275         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";");\r
276 \r
277         jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object);\r
278         jsize len = (*env)->GetStringLength(env, string);\r
279         const jchar *chars = (*env)->GetStringChars(env, string, NULL);\r
280 \r
281         PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);\r
282 \r
283         (*env)->ReleaseStringChars(env, string, chars);\r
284         return value;\r
285 }\r
286 \r
287 PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) {\r
288         jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS);\r
289         jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");\r
290         jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");\r
291         jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");\r
292 \r
293         jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS);\r
294         jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";");\r
295         jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I");\r
296 \r
297         jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);\r
298         jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");\r
299 \r
300         jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);\r
301         jint n = (*env)->CallIntMethod(env, type, getComponentCount);\r
302         jint i;\r
303 \r
304         PyObject *result = PyDict_New();\r
305         for (i = 0; i < n; i++) {\r
306                 jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i);\r
307                 jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField);\r
308                 jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i);\r
309                 jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i);\r
310 \r
311                 PyObject *item = getPythonObject(env, componentObject, componentBinding);\r
312                 PyDict_SetItem(result, getPythonString(env, fieldName), item);\r
313         }\r
314 \r
315         return result;\r
316 }\r
317 \r
318 PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) {\r
319         jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS);\r
320         jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");\r
321         jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");\r
322         jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");\r
323 \r
324         jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);\r
325 \r
326         jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);\r
327 \r
328         PyObject *result = PyList_New(size);\r
329 \r
330         jint i;\r
331         for (i = 0; i < size; i++) {\r
332                 jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i);\r
333                 if (item != NULL)\r
334                         PyList_SetItem(result, i, getPythonObject(env, item, componentBinding));\r
335                 else\r
336                         PyList_SetItem(result, i, Py_None);\r
337         }\r
338 \r
339         return result;\r
340 }\r
341 \r
342 PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) {\r
343         jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS);\r
344         jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS);\r
345         jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";");\r
346         jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";");\r
347         jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");\r
348         jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V");\r
349 \r
350         jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod);\r
351         jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod);\r
352 \r
353         jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);\r
354         jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL);\r
355         jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL);\r
356 \r
357         PyObject *result = PyDict_New();\r
358         jint i;\r
359 \r
360         (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values);\r
361 \r
362         for (i = 0; i < size; i++) {\r
363                 jobject key = (*env)->GetObjectArrayElement(env, keys, i);\r
364                 jobject item = (*env)->GetObjectArrayElement(env, values, i);\r
365                 PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding));\r
366         }\r
367 \r
368         (*env)->DeleteLocalRef(env, keys);\r
369         (*env)->DeleteLocalRef(env, values);\r
370 \r
371         return result;\r
372 }\r
373 \r
374 PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) {\r
375         jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS);\r
376         jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z");\r
377 \r
378         jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object);\r
379 \r
380         if (hasValue) {\r
381                 jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");\r
382                 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
383 \r
384                 jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);\r
385                 jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);\r
386 \r
387                 return getPythonObject(env, value, componentBinding);\r
388         }\r
389         else {\r
390                 return Py_None;\r
391         }\r
392 }\r
393 \r
394 PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) {\r
395         jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS);\r
396         jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");\r
397         jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I");\r
398         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
399         jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");\r
400 \r
401         jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS);\r
402         jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";");\r
403 \r
404         jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);\r
405         jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");\r
406 \r
407         jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object);\r
408         jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);\r
409 \r
410         jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);\r
411         jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag);\r
412         jstring compName = (*env)->GetObjectField(env, typeComponent, nameField);\r
413 \r
414         jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag);\r
415 \r
416         PyObject *result = PyTuple_New(2);\r
417         PyTuple_SetItem(result, 0, getPythonString(env, compName));\r
418         PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding));\r
419 \r
420         return result;\r
421 }\r
422 \r
423 PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) {\r
424         jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS);\r
425         jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
426         jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";");\r
427 \r
428         jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object);\r
429         jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object);\r
430 \r
431         return getPythonObject(env, content, contentBinding);\r
432 }\r
433 \r
434 PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) {\r
435         jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS);\r
436         jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS);\r
437         jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS);\r
438         jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS);\r
439         jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS);\r
440         jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS);\r
441         jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS);\r
442         jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS);\r
443         jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS);\r
444         jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS);\r
445         jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS);\r
446         jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS);\r
447         jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS);\r
448 \r
449         if (value == NULL)\r
450                 return Py_None;\r
451 \r
452         if ((*env)->IsInstanceOf(env, binding, booleanBinding)) {\r
453                 return getPythonBooleanObject(env, value, binding);\r
454         }\r
455         else if ((*env)->IsInstanceOf(env, binding, byteBinding)) {\r
456                 return getPythonByteObject(env, value, binding);\r
457         }\r
458         else if ((*env)->IsInstanceOf(env, binding, integerBinding)) {\r
459                 return getPythonIntegerObject(env, value, binding);\r
460         }\r
461         else if ((*env)->IsInstanceOf(env, binding, longBinding)) {\r
462                 return getPythonLongObject(env, value, binding);\r
463         }\r
464         else if ((*env)->IsInstanceOf(env, binding, floatBinding)) {\r
465                 return getPythonFloatObject(env, value, binding);\r
466         }\r
467         else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) {\r
468                 return getPythonDoubleObject(env, value, binding);\r
469         }\r
470         else if ((*env)->IsInstanceOf(env, binding, stringBinding)) {\r
471                 return getPythonStringObject(env, value, binding);\r
472         }\r
473         else if ((*env)->IsInstanceOf(env, binding, recordBinding)) {\r
474                 return getPythonRecordObject(env, value, binding);\r
475         }\r
476         else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) {\r
477                 return getPythonArrayObject(env, value, binding);\r
478         }\r
479         else if ((*env)->IsInstanceOf(env, binding, mapBinding)) {\r
480                 return getPythonMapObject(env, value, binding);\r
481         }\r
482         else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) {\r
483                 return getPythonOptionalObject(env, value, binding);\r
484         }\r
485         else if ((*env)->IsInstanceOf(env, binding, untionBinding)) {\r
486                 return getPythonUnionObject(env, value, binding);\r
487         }\r
488         else if ((*env)->IsInstanceOf(env, binding, variantBinding)) {\r
489                 return getPythonVariantObject(env, value, binding);\r
490         }\r
491         else {\r
492                 return Py_None;\r
493         }\r
494 }\r
495 \r
496 void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) {\r
497         if (name && value) {\r
498                 PyDict_SetItem(PyModule_GetDict(module), name, value);\r
499         }\r
500 \r
501         Py_XDECREF(name);\r
502         Py_XDECREF(value);\r
503 }\r
504 \r
505 static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {\r
506         if (d == nd) {\r
507                 ncont[d] = 1;\r
508                 return 1;\r
509         }\r
510         else {\r
511                 npy_intp n = nContiguous(d+1, nd, strides, dims, ncont);\r
512                 ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0;\r
513                 return ncont[d];\r
514         }\r
515 }\r
516 \r
517 static void copyDoubleArrayValues(JNIEnv *env, jdoubleArray array, double *data, npy_intp *offset, int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {\r
518         if (ncont[d] > 0) {\r
519                 (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data);\r
520                 *offset += ncont[d];\r
521         }\r
522         else {\r
523                 int i;\r
524                 for (i = 0; i < dims[d]; i++) {\r
525                         copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont);\r
526                 }\r
527         }\r
528 }\r
529 \r
530 jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) {\r
531         jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean");\r
532         jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;");\r
533 \r
534         return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True));\r
535 }\r
536 \r
537 jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) {\r
538         jclass longClass = (*env)->FindClass(env, "java/lang/Long");\r
539         jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;");\r
540 \r
541         return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value));\r
542 }\r
543 \r
544 jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) {\r
545         jclass doubleClass = (*env)->FindClass(env, "java/lang/Double");\r
546         jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;");\r
547 \r
548         return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value));\r
549 }\r
550 \r
551 jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) {\r
552         Py_ssize_t size = PyByteArray_Size(value);\r
553         jbyteArray result = (*env)->NewByteArray(env, (jsize)size);\r
554         char *bytes = PyByteArray_AsString(value);\r
555 \r
556         (*env)->SetByteArrayRegion(env, result, 0, size, bytes);\r
557 \r
558         return result;\r
559 }\r
560 \r
561 jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) {\r
562         PyObject *utf16Value = PyUnicode_AsUTF16String(string);\r
563         Py_ssize_t len = PyBytes_Size(utf16Value) / 2;\r
564         char *bytes = PyBytes_AsString(utf16Value);\r
565 \r
566         // Create Java string, skipping the byte order mark in the beginning\r
567         jstring result = (*env)->NewString(env, (jchar *)bytes + 1, (jsize)min(len, JAVA_MAXINT) - 1);\r
568 \r
569         Py_XDECREF(utf16Value);\r
570 \r
571         return result;\r
572 }\r
573 \r
574 jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) {\r
575         Py_ssize_t len = PySequence_Size(seq);\r
576         jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
577         jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL);\r
578 \r
579         jint i;\r
580 \r
581         for (i = 0; i < jlen; i++) {\r
582                 PyObject *item = PySequence_GetItem(seq, i);\r
583                 if (PyUnicode_Check(item)) {\r
584                         jstring value = pythonStringAsJavaString(env, item);\r
585                         (*env)->SetObjectArrayElement(env, array, i, value);\r
586                 }\r
587                 else {\r
588                         throwPythonException(env, "List item not a string");\r
589                         return NULL;\r
590                 }\r
591         }\r
592 \r
593         return array;\r
594 }\r
595 \r
596 jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) {\r
597         Py_ssize_t len = PySequence_Size(seq);\r
598         jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
599         jdoubleArray array = (*env)->NewDoubleArray(env, jlen);\r
600 \r
601         jint i;\r
602 \r
603         for (i = 0; i < jlen; i++) {\r
604                 PyObject *item = PySequence_GetItem(seq, i);\r
605                 if (PyFloat_Check(item)) {\r
606                         double value = PyFloat_AsDouble(item);\r
607                         (*env)->SetDoubleArrayRegion(env, array, i, 1, &value);\r
608                 }\r
609                 else {\r
610                         throwPythonException(env, "List item not a floating point value");\r
611                         return NULL;\r
612                 }\r
613         }\r
614 \r
615         return array;\r
616 }\r
617 \r
618 jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) {\r
619         if (PyBool_Check(value))\r
620                 return pythonBoolAsBooleanObject(env, value);\r
621         else if (PyLong_Check(value))\r
622                 return pythonLongAsLongObject(env, value);\r
623         else if (PyFloat_Check(value))\r
624                 return pythonFloatAsDoubleObject(env, value);\r
625         else if (PyUnicode_Check(value))\r
626                 return pythonStringAsJavaString(env, value);\r
627         else if (PyByteArray_Check(value))\r
628                 return pythonByteArrayAsByteArray(env, value);\r
629         else if (PyDict_Check(value))\r
630                 return pythonDictionaryAsMap(env, value);\r
631         else if (hasNumpy && PyArray_Check(value))\r
632                 return pythonArrayAsNDArray(env, (PyArrayObject *)value);\r
633         else if (PySequence_Check(value))\r
634                 return pythonSequenceAsObjectArray(env, value);\r
635         else\r
636                 return NULL;\r
637 }\r
638 \r
639 jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) {\r
640         Py_ssize_t len = PySequence_Size(seq);\r
641         jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
642         jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL);\r
643 \r
644         jint i;\r
645 \r
646         for (i = 0; i < jlen; i++) {\r
647                 PyObject *item = PySequence_GetItem(seq, i);\r
648                 jobject object = pythonObjectAsObject(env, item);\r
649                 (*env)->SetObjectArrayElement(env, array, i, object);\r
650         }\r
651 \r
652         return array;\r
653 }\r
654 \r
655 jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) {\r
656         Py_ssize_t len = PySequence_Size(seq);\r
657         jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
658         jbooleanArray array = (*env)->NewBooleanArray(env, jlen);\r
659 \r
660         jint i;\r
661 \r
662         for (i = 0; i < jlen; i++) {\r
663                 PyObject *item = PySequence_GetItem(seq, i);\r
664                 if (PyBool_Check(item)) {\r
665                         jboolean value = item == Py_True;\r
666                         (*env)->SetBooleanArrayRegion(env, array, i, 1, &value);\r
667                 }\r
668                 else {\r
669                         throwPythonException(env, "List item not a boolean");\r
670                         return NULL;\r
671                 }\r
672         }\r
673 \r
674         return array;\r
675 }\r
676 \r
677 jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) {\r
678         Py_ssize_t len = PySequence_Size(seq);\r
679         jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
680         jintArray array = (*env)->NewIntArray(env, jlen);\r
681 \r
682         jint i;\r
683 \r
684         for (i = 0; i < jlen; i++) {\r
685                 PyObject *item = PySequence_GetItem(seq, i);\r
686                 if (PyLong_Check(item)) {\r
687                         jint value = PyLong_AsLong(item);\r
688                         (*env)->SetIntArrayRegion(env, array, i, 1, &value);\r
689                 }\r
690                 else {\r
691                         throwPythonException(env, "List item not an integer");\r
692                         return NULL;\r
693                 }\r
694         }\r
695 \r
696         return array;\r
697 }\r
698 \r
699 jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) {\r
700         Py_ssize_t len = PySequence_Size(seq);\r
701         jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
702         jlongArray array = (*env)->NewLongArray(env, jlen);\r
703 \r
704         jint i;\r
705 \r
706         for (i = 0; i < jlen; i++) {\r
707                 PyObject *item = PySequence_GetItem(seq, i);\r
708                 if (PyLong_Check(item)) {\r
709                         jlong value = PyLong_AsLongLong(item);\r
710                         (*env)->SetLongArrayRegion(env, array, i, 1, &value);\r
711                 }\r
712                 else {\r
713                         throwPythonException(env, "List item not an integer");\r
714                         return NULL;\r
715                 }\r
716         }\r
717 \r
718         return array;\r
719 }\r
720 \r
721 jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) {\r
722         jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);\r
723         jmethodID constructor = (*env)->GetMethodID(env, ndarrayClass, "<init>", "([I[D)V");\r
724 \r
725         int ndims = PyArray_NDIM(array);\r
726         npy_intp *dims = PyArray_DIMS(array);\r
727 \r
728         npy_intp len = PyArray_Size((PyObject*)array);\r
729         double *values = (double*)PyArray_DATA(array);\r
730 \r
731         jboolean isFortran = PyArray_ISFORTRAN(array) != 0;\r
732 \r
733         int i;\r
734 \r
735         if (len > JAVA_MAXINT) {\r
736                 throwPythonException(env, "Array too large");\r
737                 return NULL;\r
738         }\r
739 \r
740         {\r
741                 jintArray jdims = (*env)->NewIntArray(env, ndims);\r
742                 jdoubleArray jvalues = (*env)->NewDoubleArray(env, (jsize)len);\r
743 \r
744                 for (i = 0; i < ndims; i++) {\r
745                         jint dim = (jint)dims[i];\r
746                         (*env)->SetIntArrayRegion(env, jdims, i, 1, &dim);\r
747                 }\r
748 \r
749                 if (PyArray_IS_C_CONTIGUOUS(array)) {\r
750                         (*env)->SetDoubleArrayRegion(env, jvalues, 0, (jsize)len, values);\r
751                 }\r
752                 else {\r
753                         npy_intp offset = 0;\r
754                         npy_intp *strides = PyArray_STRIDES(array);\r
755                         npy_intp *ncont = (npy_intp*)malloc((ndims + 1) * sizeof(npy_intp));\r
756                         nContiguous(0, ndims, strides, dims, ncont);\r
757                         copyDoubleArrayValues(env, jvalues, values, &offset, 0, ndims, strides, dims, ncont);\r
758                         free(ncont);\r
759                 }\r
760 \r
761                 return (*env)->NewObject(env, ndarrayClass, constructor, jdims, jvalues, isFortran);\r
762         }\r
763 }\r
764 \r
765 jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) {\r
766         jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap");\r
767         jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "<init>", "(I)V");\r
768         jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
769 \r
770         Py_ssize_t size = PyDict_Size(dict);\r
771         jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size);\r
772 \r
773         PyObject *key, *value;\r
774         Py_ssize_t pos = 0;\r
775 \r
776         while (PyDict_Next(dict, &pos, &key, &value)) {\r
777                 jobject keyObject = pythonObjectAsObject(env, key);\r
778                 jobject valueObject = pythonObjectAsObject(env, value);\r
779                 (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject);\r
780         }\r
781 \r
782         return map;\r
783 }\r
784 \r
785 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jboolean value) {\r
786         PyObject *module = (PyObject*)contextID;\r
787 \r
788         PyObject *pythonName = getPythonString(env, variableName);\r
789         PyObject *val = getPythonBool(value);\r
790 \r
791         setPythonVariable(module, pythonName, val);\r
792 }\r
793 \r
794 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jbooleanArray value) {\r
795         PyObject *module = (PyObject*)contextID;\r
796 \r
797         PyObject *pythonName = getPythonString(env, variableName);\r
798         PyObject *val = getPythonBooleanList(env, value);\r
799 \r
800         setPythonVariable(module, pythonName, val);\r
801 }\r
802 \r
803 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlong value) {\r
804         PyObject *module = (PyObject*)contextID;\r
805 \r
806         PyObject *pythonName = getPythonString(env, variableName);\r
807         PyObject *val = PyLong_FromLongLong(value);\r
808 \r
809         setPythonVariable(module, pythonName, val);\r
810 }\r
811 \r
812 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jintArray value) {\r
813         PyObject *module = (PyObject*)contextID;\r
814 \r
815         PyObject *pythonName = getPythonString(env, variableName);\r
816         PyObject *val = getPythonIntegerList(env, value);\r
817 \r
818         setPythonVariable(module, pythonName, val);\r
819 }\r
820 \r
821 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlongArray value) {\r
822         PyObject *module = (PyObject*)contextID;\r
823 \r
824         PyObject *pythonName = getPythonString(env, variableName);\r
825         PyObject *val = getPythonLongList(env, value);\r
826 \r
827         setPythonVariable(module, pythonName, val);\r
828 }\r
829 \r
830 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdouble value) {\r
831         PyObject *module = (PyObject*)contextID;\r
832 \r
833         PyObject *pythonName = getPythonString(env, variableName);\r
834         PyObject *val = PyFloat_FromDouble(value);\r
835 \r
836         setPythonVariable(module, pythonName, val);\r
837 }\r
838 \r
839 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonFloatArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jfloatArray value) {\r
840         PyObject *module = (PyObject*)contextID;\r
841 \r
842         PyObject *pythonName = getPythonString(env, variableName);\r
843         PyObject *val = getPythonFloatList(env, value);\r
844 \r
845         setPythonVariable(module, pythonName, val);\r
846 }\r
847 \r
848 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdoubleArray value) {\r
849         PyObject *module = (PyObject*)contextID;\r
850 \r
851         PyObject *pythonName = getPythonString(env, variableName);\r
852         PyObject *val = getPythonDoubleList(env, value);\r
853 \r
854         setPythonVariable(module, pythonName, val);\r
855 }\r
856 \r
857 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonStringVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jstring value) {\r
858         PyObject *module = (PyObject*)contextID;\r
859 \r
860         PyObject *pythonName = getPythonString(env, variableName);\r
861         PyObject *val = getPythonString(env, value);\r
862 \r
863         setPythonVariable(module, pythonName, val);\r
864 }\r
865 \r
866 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobjectArray value) {\r
867         PyObject *module = (PyObject*)contextID;\r
868 \r
869         PyObject *pythonName = getPythonString(env, variableName);\r
870         PyObject *val = getPythonStringList(env, value);\r
871 \r
872         setPythonVariable(module, pythonName, val);\r
873 }\r
874 \r
875 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value) {\r
876         PyObject *module = (PyObject*)contextID;\r
877 \r
878         if (!hasNumpy) {\r
879                 throwPythonException(env, "Importing numpy failed");\r
880                 return;\r
881         }\r
882 \r
883         {\r
884                 PyObject *pythonName = getPythonString(env, variableName);\r
885                 PyObject *val = getPythonNDArray(env, value);\r
886 \r
887                 setPythonVariable(module, pythonName, val);\r
888         }\r
889 }\r
890 \r
891 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value, jobject binding) {\r
892         PyObject *module = (PyObject*)contextID;\r
893 \r
894         PyObject *pythonName = getPythonString(env, variableName);\r
895         PyObject *val = getPythonObject(env, value, binding);\r
896 \r
897         setPythonVariable(module, pythonName, val);\r
898 }\r
899 \r
900 JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) {\r
901         PyObject *module = (PyObject*)contextID;\r
902 \r
903         const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL);\r
904 \r
905         PyErr_Clear();\r
906         {\r
907                 PyObject *globals;\r
908 \r
909                 globals = PyModule_GetDict(module);\r
910 \r
911                 {\r
912                         PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals);\r
913 \r
914                         PyObject *exceptionType = PyErr_Occurred();\r
915                         if (exceptionType != NULL) {\r
916                                 PyObject *exception, *traceback;\r
917                                 PyErr_Fetch(&exceptionType, &exception, &traceback);\r
918 \r
919                                 {\r
920                                         PyObject *tracebackModule = PyImport_ImportModule("traceback");\r
921                                         if (tracebackModule != NULL) {\r
922                                                 PyObject *formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception");\r
923                                                 if (formatExc != NULL) {\r
924                                                         PyObject *args = PyTuple_Pack(3, exceptionType, exception, traceback);\r
925                                                         PyObject *message = PyObject_CallObject(formatExc, args);\r
926                                                         if (message != NULL) {\r
927                                                                 PyObject *emptyStr = PyUnicode_FromString("");\r
928                                                                 PyObject *joined = PyUnicode_Join(emptyStr, message);\r
929                                                                 char *messageStr = PyUnicode_AsUTF8(joined);\r
930                                                                 throwPythonException(env, messageStr);\r
931                                                                 Py_DECREF(joined);\r
932                                                                 Py_DECREF(emptyStr);\r
933                                                                 Py_DECREF(message);\r
934                                                         }\r
935                                                         else {\r
936                                                                 throwPythonException(env, "Internal error, no message");\r
937                                                         }\r
938                                                         Py_DECREF(args);\r
939                                                         Py_DECREF(formatExc);\r
940                                                 }\r
941                                                 else {\r
942                                                         throwPythonException(env, "Internal error, no format_exc function");\r
943                                                 }\r
944                                                 Py_DECREF(tracebackModule);\r
945                                         }\r
946                                         else {\r
947                                                 throwPythonException(env, "Internal error, no traceback module");\r
948                                         }\r
949                                 }\r
950                         }\r
951 \r
952                         (*env)->ReleaseStringUTFChars(env, statement, utfchars);\r
953 \r
954                         return result != NULL ? 0 : 1;\r
955                 }\r
956         }\r
957 }\r
958 \r
959 JNIEXPORT jstring JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
960         PyObject *module = (PyObject*)contextID;\r
961 \r
962         PyObject *pythonName = getPythonString(env, variableName);\r
963 \r
964         PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
965         if (value == NULL) {\r
966                 throwPythonException(env, "Python variable not found");\r
967                 return 0;\r
968         }\r
969 \r
970         if (!PyUnicode_Check(value)) {\r
971                 throwPythonException(env, "Python variable not a string");\r
972                 return 0;\r
973         }\r
974 \r
975         {\r
976                 jstring result = pythonStringAsJavaString(env, value);\r
977                 return result;\r
978         }\r
979 }\r
980 \r
981 JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
982         PyObject *module = (PyObject*)contextID;\r
983 \r
984         PyObject *pythonName = getPythonString(env, variableName);\r
985 \r
986         PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
987         if (value == NULL) {\r
988                 throwPythonException(env, "Python variable not found");\r
989                 return 0;\r
990         }\r
991 \r
992         if (!PySequence_Check(value)) {\r
993                 throwPythonException(env, "Python variable not a sequence");\r
994                 return 0;\r
995         }\r
996 \r
997         {\r
998                 jobjectArray result = pythonSequenceAsStringArray(env, value);\r
999                 return result;\r
1000         }\r
1001 }\r
1002 \r
1003 JNIEXPORT jboolean JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
1004         PyObject *module = (PyObject*)contextID;\r
1005 \r
1006         PyObject *pythonName = getPythonString(env, variableName);\r
1007 \r
1008         PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
1009         if (value == NULL) {\r
1010                 throwPythonException(env, "Python variable not found");\r
1011                 return 0;\r
1012         }\r
1013 \r
1014         if (!PyBool_Check(value)) {\r
1015                 throwPythonException(env, "Python variable not a boolean");\r
1016                 return 0;\r
1017         }\r
1018 \r
1019         return value == Py_True;\r
1020 }\r
1021 \r
1022 JNIEXPORT jbooleanArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
1023         PyObject *module = (PyObject*)contextID;\r
1024 \r
1025         PyObject *pythonName = getPythonString(env, variableName);\r
1026 \r
1027         PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
1028         if (value == NULL) {\r
1029                 throwPythonException(env, "Python variable not found");\r
1030                 return 0;\r
1031         }\r
1032 \r
1033         if (!PySequence_Check(value)) {\r
1034                 throwPythonException(env, "Python variable not a sequence");\r
1035                 return 0;\r
1036         }\r
1037 \r
1038         {\r
1039                 jbooleanArray result = pythonSequenceAsBooleanArray(env, value);\r
1040                 return result;\r
1041         }\r
1042 }\r
1043 \r
1044 JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
1045         PyObject *module = (PyObject*)contextID;\r
1046 \r
1047         PyObject *pythonName = getPythonString(env, variableName);\r
1048 \r
1049         PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
1050         if (value == NULL) {\r
1051                 throwPythonException(env, "Python variable not found");\r
1052                 return 0;\r
1053         }\r
1054 \r
1055         if (!PyLong_Check(value)) {\r
1056                 throwPythonException(env, "Python variable not an integer");\r
1057                 return 0;\r
1058         }\r
1059 \r
1060         {\r
1061                 jlong result = PyLong_AsLongLong(value);\r
1062                 return result;\r
1063         }\r
1064 }\r
1065 \r
1066 JNIEXPORT jintArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
1067         PyObject *module = (PyObject*)contextID;\r
1068 \r
1069         PyObject *pythonName = getPythonString(env, variableName);\r
1070 \r
1071         PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
1072         if (value == NULL) {\r
1073                 throwPythonException(env, "Python variable not found");\r
1074                 return NULL;\r
1075         }\r
1076 \r
1077         if (!PySequence_Check(value)) {\r
1078                 throwPythonException(env, "Python variable not a sequence");\r
1079                 return NULL;\r
1080         }\r
1081 \r
1082         {\r
1083                 jintArray result = pythonSequenceAsIntegerArray(env, value);\r
1084                 return result;\r
1085         }\r
1086 }\r
1087 \r
1088 JNIEXPORT jlongArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
1089         PyObject *module = (PyObject*)contextID;\r
1090 \r
1091         PyObject *pythonName = getPythonString(env, variableName);\r
1092 \r
1093         PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
1094         if (value == NULL) {\r
1095                 throwPythonException(env, "Python variable not found");\r
1096                 return NULL;\r
1097         }\r
1098 \r
1099         if (!PySequence_Check(value)) {\r
1100                 throwPythonException(env, "Python variable not a sequence");\r
1101                 return NULL;\r
1102         }\r
1103 \r
1104         {\r
1105                 jlongArray result = pythonSequenceAsLongArray(env, value);\r
1106                 return result;\r
1107         }\r
1108 }\r
1109 \r
1110 JNIEXPORT jdouble JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
1111         PyObject *module = (PyObject*)contextID;\r
1112 \r
1113         PyObject *pythonName = getPythonString(env, variableName);\r
1114 \r
1115         PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
1116         if (value == NULL) {\r
1117                 throwPythonException(env, "Python variable not found");\r
1118                 return 0.0;\r
1119         }\r
1120 \r
1121         if (!PyFloat_Check(value)) {\r
1122                 throwPythonException(env, "Python variable not a float");\r
1123                 return 0.0;\r
1124         }\r
1125 \r
1126         {\r
1127                 jdouble result = PyFloat_AsDouble(value);\r
1128                 return result;\r
1129         }\r
1130 }\r
1131 \r
1132 JNIEXPORT jdoubleArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
1133         PyObject *module = (PyObject*)contextID;\r
1134 \r
1135         PyObject *pythonName = getPythonString(env, variableName);\r
1136 \r
1137         PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
1138         if (value == NULL) {\r
1139                 throwPythonException(env, "Python variable not found");\r
1140                 return NULL;\r
1141         }\r
1142 \r
1143         if (!PySequence_Check(value)) {\r
1144                 throwPythonException(env, "Python variable not a sequence");\r
1145                 return NULL;\r
1146         }\r
1147 \r
1148         {\r
1149                 jdoubleArray result = pythonSequenceAsDoubleArray(env, value);\r
1150                 return result;\r
1151         }\r
1152 }\r
1153 \r
1154 JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
1155         PyObject *module = (PyObject*)contextID;\r
1156 \r
1157         if (!hasNumpy) {\r
1158                 throwPythonException(env, "Importing numpy failed");\r
1159                 return NULL;\r
1160         }\r
1161 \r
1162         {\r
1163                 PyObject *pythonName = getPythonString(env, variableName);\r
1164 \r
1165                 PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
1166                 if (value == NULL) {\r
1167                         throwPythonException(env, "Python variable not found");\r
1168                         return NULL;\r
1169                 }\r
1170 \r
1171                 if (!PyArray_Check(value)) {\r
1172                         throwPythonException(env, "Python variable not an ndarray");\r
1173                         return NULL;\r
1174                 }\r
1175 \r
1176                 if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) {\r
1177                         throwPythonException(env, "Only ndarrays of type double are supported");\r
1178                         return NULL;\r
1179                 }\r
1180 \r
1181                 {\r
1182                         jobject result = pythonArrayAsNDArray(env, (PyArrayObject *)value);\r
1183                         return result;\r
1184                 }\r
1185         }\r
1186 }\r
1187 \r
1188 JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
1189         PyObject *module = (PyObject*)contextID;\r
1190 \r
1191         PyObject *pythonName = getPythonString(env, variableName);\r
1192 \r
1193         PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
1194         if (value == NULL) {\r
1195                 throwPythonException(env, "Python variable not found");\r
1196                 return NULL;\r
1197         }\r
1198 \r
1199         hasNumpy = _import_array() != -1;\r
1200 \r
1201         {\r
1202                 jobject result = pythonObjectAsObject(env, value);\r
1203                 return result;\r
1204         }\r
1205 }\r
1206 \r
1207 JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
1208         PyObject *module = (PyObject*)contextID;\r
1209         PyObject *dict = PyModule_GetDict(module);\r
1210 \r
1211         PyObject *pythonName = getPythonString(env, variableName);\r
1212 \r
1213         if (!PyDict_Contains(dict, pythonName)) {\r
1214                 return 0;\r
1215         }\r
1216 \r
1217         {\r
1218                 PyObject *value = PyDict_GetItem(dict, pythonName);\r
1219 \r
1220                 jint result;\r
1221 \r
1222                 if (PyBool_Check(value))\r
1223                         result = 1;\r
1224                 else if (PyLong_Check(value))\r
1225                         result = 2;\r
1226                 else if (PyFloat_Check(value))\r
1227                         result = 3;\r
1228                 else if (PyUnicode_Check(value))\r
1229                         result = 4;\r
1230                 else if (PyByteArray_Check(value))\r
1231                         result = 5;\r
1232                 else if (PyDict_Check(value))\r
1233                         result = 6;\r
1234                 else if (hasNumpy && PyArray_Check(value))\r
1235                         result = 7;\r
1236                 else if (PySequence_Check(value))\r
1237                         result = 8;\r
1238                 else\r
1239                         result = -1;\r
1240 \r
1241                 return result;\r
1242         }\r
1243 }\r
1244 \r
1245 JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(JNIEnv *env, jobject thisObj, jlong contextID) {\r
1246         PyObject *module = (PyObject*)contextID;\r
1247         PyObject *dict = PyModule_GetDict(module);\r
1248 \r
1249         PyObject *keys = PyDict_Keys(dict);\r
1250         Py_ssize_t size = PyList_Size(keys);\r
1251 \r
1252         jobjectArray result = (*env)->NewObjectArray(env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL);\r
1253 \r
1254         Py_ssize_t i;\r
1255         for (i = 0; i < size; i++) {\r
1256                 jstring javaName = pythonStringAsJavaString(env, PyList_GetItem(keys, i));\r
1257                 (*env)->SetObjectArrayElement(env, result, (jint)i, javaName);\r
1258         }\r
1259 \r
1260         Py_XDECREF(keys);\r
1261 \r
1262         return result;\r
1263 }\r
1264 \r
1265 BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)\r
1266 //extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)\r
1267 {\r
1268     switch (fdwReason)\r
1269     {\r
1270         case DLL_PROCESS_ATTACH:\r
1271             // attach to process\r
1272             // return FALSE to fail DLL load\r
1273             break;\r
1274 \r
1275         case DLL_PROCESS_DETACH:\r
1276             // detach from process\r
1277             break;\r
1278 \r
1279         case DLL_THREAD_ATTACH:\r
1280             // attach to thread\r
1281             break;\r
1282 \r
1283         case DLL_THREAD_DETACH:\r
1284             // detach from thread\r
1285             break;\r
1286     }\r
1287     return TRUE; // succesful\r
1288 }\r