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