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