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