]> gerrit.simantics Code Review - simantics/python.git/blobdiff - org.simantics.pythonlink.win32.x86_64/src/sclpy.c
Merge branch 'change/300/2'
[simantics/python.git] / org.simantics.pythonlink.win32.x86_64 / src / sclpy.c
index a6c64abf183e2b68b3a9ab48e54bccbd26172723..4881cc7d7c26d4a20979542530230724dc1df5f2 100644 (file)
-///////////////////////////////////////////////////////\r
-//                                                   //\r
-//   VTT Technical Research Centre of Finland LTD    //\r
-//   For internal use only. Do not redistribute.     //\r
-//                                                   //\r
-//   Authors:                                        //\r
-//       Antton Tapani    ext-antton.tapani@vtt.fi   //\r
-//                                                   //\r
-//   Last modified by Antton Tapani    9.2016        //\r
-//                                                   //\r
-///////////////////////////////////////////////////////\r
-\r
-#include "sclpy.h"\r
-\r
-#include <windows.h>\r
-\r
-jint throwException( JNIEnv *env, char *className, char *message )\r
-{\r
-    jclass exClass = (*env)->FindClass( env, className);\r
-    if (exClass == NULL) {\r
-        return 0;\r
-    }\r
-\r
-    return (*env)->ThrowNew( env, exClass, message );\r
-}\r
-\r
-jint throwPythonException( JNIEnv *env, char *message ) {\r
-       return throwException( env, PYTHON_EXCEPTION, message );\r
-}\r
-\r
-jint throwIllegalArgumentException( JNIEnv *env, char *message ) {\r
-       return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message );\r
-}\r
-\r
-PyObject* getModule(jlong contextID) {\r
-       return PyState_FindModule((PyModuleDef*) contextID);\r
-//     return PyImport_AddModule("__main__");\r
-}\r
-\r
-int moduleCount = 0;\r
-int initCalled = 0;\r
-int hasNumpy = 0;\r
-\r
-static JNIEnv *currentEnv = NULL;\r
-jobject sclWriter = NULL;\r
-\r
-static PyObject *\r
-writeToSCL(PyObject *self, PyObject *args)\r
-{\r
-    if (currentEnv != NULL && sclWriter != NULL) {\r
-       JNIEnv *env = currentEnv;\r
-\r
-               Py_UNICODE *what;\r
-               Py_ssize_t length;\r
-               if (!PyArg_ParseTuple(args, "u#", &what, &length))\r
-                       return NULL;\r
-\r
-               {\r
-               jclass writerClass = (*env)->FindClass(env, WRITER_CLASS);\r
-               jmethodID writeMethod = (*env)->GetMethodID(env, writerClass, "write", "([CII)V");\r
-               jcharArray chars = (*env)->NewCharArray(env, (jsize)length);\r
-\r
-               (*env)->SetCharArrayRegion(env, chars, 0, length, what);\r
-               (*env)->CallVoidMethod(env, sclWriter, writeMethod, chars, 0, length);\r
-               }\r
-    }\r
-\r
-    return Py_BuildValue("");\r
-}\r
-\r
-static PyMethodDef sclWriterMethods[] = {\r
-    {"write", writeToSCL, METH_VARARGS, "Write something."},\r
-    {NULL, NULL, 0, NULL}\r
-};\r
-\r
-\r
-JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) {\r
-       char name[16];\r
-\r
-       if (!initCalled) {\r
-        Py_Initialize();\r
-        initCalled = 1;\r
-\r
-        {\r
-               static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods, };\r
-                       PyObject *m = PyModule_Create(&moduledef);\r
-\r
-               if (m == NULL) throwException(env, PYTHON_EXCEPTION, "Failed to create SCL writer module");\r
-                       PySys_SetObject("stdout", m);\r
-                       PySys_SetObject("stderr", m);\r
-        }\r
-\r
-       hasNumpy = _import_array();\r
-       hasNumpy = hasNumpy != -1;\r
-       }\r
-\r
-       sprintf(name, "SCL_%d", ++moduleCount);\r
-\r
-       {\r
-               PyObject *module;\r
-               PyModuleDef *modDef = malloc(sizeof(PyModuleDef));\r
-               memset(modDef, 0, sizeof(PyModuleDef));\r
-               modDef->m_name = strdup(name);\r
-               modDef->m_doc = NULL;\r
-               modDef->m_size = -1;\r
-\r
-               module = PyModule_Create(modDef);\r
-               Py_INCREF(module);\r
-               PyState_AddModule(module, modDef);\r
-\r
-               {\r
-                       PyObject *builtin = PyImport_AddModule("builtins");\r
-                       PyObject *dict = PyModule_GetDict(module);\r
-                       PyDict_SetItemString(dict, "__builtin__", builtin);\r
-                       PyDict_SetItemString(dict, "__builtins__", builtin);\r
-\r
-                       return (jlong)modDef;\r
-               }\r
-       }\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) {\r
-       PyModuleDef *modDef = (PyModuleDef*)contextID;\r
-       PyObject *module = PyState_FindModule(modDef);\r
-       Py_XDECREF(module);\r
-       PyState_RemoveModule(modDef);\r
-       free((char*)modDef->m_name);\r
-       free(modDef);\r
-}\r
-\r
-PyObject *getPythonBool(jboolean value) {\r
-       if (value) {\r
-               Py_RETURN_TRUE;\r
-       }\r
-       else {\r
-               Py_RETURN_FALSE;\r
-       }\r
-}\r
-\r
-PyObject *getPythonString(JNIEnv *env, jstring string) {\r
-       jsize len = (*env)->GetStringLength(env, string);\r
-       const jchar *chars = (*env)->GetStringChars(env, string, NULL);\r
-\r
-       PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);\r
-\r
-       (*env)->ReleaseStringChars(env, string, chars);\r
-       return value;\r
-}\r
-\r
-PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) {\r
-       jsize nitems = (*env)->GetArrayLength(env, value);\r
-       jint *values = (*env)->GetIntArrayElements(env, value, NULL);\r
-       jclass stringClass = (*env)->FindClass(env, STRING_CLASS);\r
-       jint i;\r
-\r
-       PyObject *result = PyList_New(nitems);\r
-       for (i = 0; i < nitems; i++) {\r
-               jobject item = (*env)->GetObjectArrayElement(env, value, i);\r
-               if (item != NULL && (*env)->IsInstanceOf(env, item, stringClass)) {\r
-                       PyList_SetItem(result, i, getPythonString(env, (jstring)item));\r
-               }\r
-               else {\r
-                       PyList_SetItem(result, i, Py_None);\r
-               }\r
-       }\r
-\r
-       (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);\r
-       return result;\r
-}\r
-\r
-PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) {\r
-       jsize nitems = (*env)->GetArrayLength(env, value);\r
-       jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL);\r
-       jint i;\r
-\r
-       PyObject *result = PyList_New(nitems);\r
-       for (i = 0; i < nitems; i++) {\r
-               PyList_SetItem(result, i, getPythonBool(values[i]));\r
-       }\r
-\r
-       (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT);\r
-       return result;\r
-}\r
-\r
-PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) {\r
-       jint len = (*env)->GetArrayLength(env, value);\r
-       jbyte *values = (*env)->GetByteArrayElements(env, value, NULL);\r
-\r
-       PyObject *result = PyByteArray_FromStringAndSize(values, len);\r
-\r
-       (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT);\r
-       return result;\r
-}\r
-\r
-PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) {\r
-       jsize nitems = (*env)->GetArrayLength(env, value);\r
-       jint *values = (*env)->GetIntArrayElements(env, value, NULL);\r
-       jint i;\r
-\r
-       PyObject *result = PyList_New(nitems);\r
-       for (i = 0; i < nitems; i++) {\r
-               PyList_SetItem(result, i, PyLong_FromLong(values[i]));\r
-       }\r
-\r
-       (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);\r
-       return result;\r
-}\r
-\r
-PyObject *getPythonLongList(JNIEnv *env, jlongArray value) {\r
-       jsize nitems = (*env)->GetArrayLength(env, value);\r
-       jlong *values = (*env)->GetLongArrayElements(env, value, NULL);\r
-       jint i;\r
-\r
-       PyObject *result = PyList_New(nitems);\r
-       for (i = 0; i < nitems; i++) {\r
-               PyList_SetItem(result, i, PyLong_FromLongLong(values[i]));\r
-       }\r
-\r
-       (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT);\r
-       return result;\r
-}\r
-\r
-PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) {\r
-       jsize nitems = (*env)->GetArrayLength(env, value);\r
-       float *values = (*env)->GetFloatArrayElements(env, value, NULL);\r
-       jint i;\r
-\r
-       PyObject *result = PyList_New(nitems);\r
-       for (i = 0; i < nitems; i++) {\r
-               PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i]));\r
-       }\r
-\r
-       (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT);\r
-       return result;\r
-}\r
-\r
-PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) {\r
-       jsize nitems = (*env)->GetArrayLength(env, value);\r
-       double *values = (*env)->GetDoubleArrayElements(env, value, NULL);\r
-       jint i;\r
-\r
-       PyObject *result = PyList_New(nitems);\r
-       for (i = 0; i < nitems; i++) {\r
-               PyList_SetItem(result, i, PyFloat_FromDouble(values[i]));\r
-       }\r
-\r
-       (*env)->ReleaseDoubleArrayElements(env, value, values, JNI_ABORT);\r
-       return result;\r
-}\r
-\r
-PyObject *getPythonNDArray(JNIEnv *env, jobject value) {\r
-       jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);\r
-       jmethodID dimsMethod = (*env)->GetMethodID(env, ndarrayClass, "dims", "()[I");\r
-       jmethodID getValuesMethod = (*env)->GetMethodID(env, ndarrayClass, "getValues", "()[D");\r
-\r
-       jintArray jdims = (*env)->CallObjectMethod(env, value, dimsMethod);\r
-       jsize ndims = (*env)->GetArrayLength(env, jdims);\r
-       jint *dims = (*env)->GetIntArrayElements(env, jdims, NULL);\r
-\r
-       jdoubleArray jvalues = (*env)->CallObjectMethod(env, value, getValuesMethod);\r
-       jsize len = (*env)->GetArrayLength(env, jvalues);\r
-       jdouble *values = (*env)->GetDoubleArrayElements(env, jvalues, NULL);\r
-\r
-       npy_intp *pyDims = (npy_intp*)malloc(ndims * sizeof(npy_intp));\r
-\r
-       jint i, nelem = ndims > 0 ? 1 : 0;\r
-       for (i = 0; i < ndims; i++) {\r
-               nelem *= dims[i];\r
-               pyDims[i] = dims[i];\r
-       }\r
-\r
-       len = min(len, nelem);\r
-\r
-       {\r
-               PyObject *array = PyArray_EMPTY(ndims, pyDims, NPY_DOUBLE, 0);\r
-               double *data = (double *)PyArray_DATA((PyArrayObject*)array);\r
-\r
-               memcpy(data, values, len * sizeof(double));\r
-\r
-               free(pyDims);\r
-\r
-               (*env)->ReleaseDoubleArrayElements(env, jvalues, values, JNI_ABORT);\r
-               (*env)->ReleaseIntArrayElements(env, jdims, dims, JNI_ABORT);\r
-\r
-               return array;\r
-       }\r
-}\r
-\r
-PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS);\r
-       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z");\r
-\r
-       jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object);\r
-       return getPythonBool(bvalue);\r
-}\r
-\r
-PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS);\r
-       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B");\r
-\r
-       jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object);\r
-       return PyLong_FromLong(v);\r
-}\r
-\r
-PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS);\r
-       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I");\r
-\r
-       jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object);\r
-       return PyLong_FromLong(v);\r
-}\r
-\r
-PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS);\r
-       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J");\r
-\r
-       jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object);\r
-       return PyLong_FromLongLong(v);\r
-}\r
-\r
-PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS);\r
-       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F");\r
-\r
-       jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object);\r
-       return PyFloat_FromDouble(v);\r
-}\r
-\r
-PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS);\r
-       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D");\r
-\r
-       jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object);\r
-       return PyFloat_FromDouble(v);\r
-}\r
-\r
-PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS);\r
-       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";");\r
-\r
-       jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object);\r
-       jsize len = (*env)->GetStringLength(env, string);\r
-       const jchar *chars = (*env)->GetStringChars(env, string, NULL);\r
-\r
-       PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);\r
-\r
-       (*env)->ReleaseStringChars(env, string, chars);\r
-       return value;\r
-}\r
-\r
-PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS);\r
-       jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");\r
-       jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");\r
-       jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");\r
-\r
-       jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS);\r
-       jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";");\r
-       jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I");\r
-\r
-       jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);\r
-       jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");\r
-\r
-       jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);\r
-       jint n = (*env)->CallIntMethod(env, type, getComponentCount);\r
-       jint i;\r
-\r
-       PyObject *result = PyDict_New();\r
-       for (i = 0; i < n; i++) {\r
-               jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i);\r
-               jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField);\r
-               jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i);\r
-               jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i);\r
-\r
-               PyObject *item = getPythonObject(env, componentObject, componentBinding);\r
-               PyDict_SetItem(result, getPythonString(env, fieldName), item);\r
-       }\r
-\r
-       return result;\r
-}\r
-\r
-PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS);\r
-       jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");\r
-       jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");\r
-       jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");\r
-\r
-       jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);\r
-\r
-       jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);\r
-\r
-       PyObject *result = PyList_New(size);\r
-\r
-       jint i;\r
-       for (i = 0; i < size; i++) {\r
-               jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i);\r
-               if (item != NULL)\r
-                       PyList_SetItem(result, i, getPythonObject(env, item, componentBinding));\r
-               else\r
-                       PyList_SetItem(result, i, Py_None);\r
-       }\r
-\r
-       return result;\r
-}\r
-\r
-PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS);\r
-       jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS);\r
-       jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";");\r
-       jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";");\r
-       jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");\r
-       jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V");\r
-\r
-       jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod);\r
-       jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod);\r
-\r
-       jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);\r
-       jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL);\r
-       jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL);\r
-\r
-       PyObject *result = PyDict_New();\r
-       jint i;\r
-\r
-       (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values);\r
-\r
-       for (i = 0; i < size; i++) {\r
-               jobject key = (*env)->GetObjectArrayElement(env, keys, i);\r
-               jobject item = (*env)->GetObjectArrayElement(env, values, i);\r
-               PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding));\r
-       }\r
-\r
-       (*env)->DeleteLocalRef(env, keys);\r
-       (*env)->DeleteLocalRef(env, values);\r
-\r
-       return result;\r
-}\r
-\r
-PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS);\r
-       jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z");\r
-\r
-       jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object);\r
-\r
-       if (hasValue) {\r
-               jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");\r
-               jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
-\r
-               jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);\r
-               jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);\r
-\r
-               return getPythonObject(env, value, componentBinding);\r
-       }\r
-       else {\r
-               return Py_None;\r
-       }\r
-}\r
-\r
-PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS);\r
-       jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");\r
-       jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I");\r
-       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
-       jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");\r
-\r
-       jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS);\r
-       jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";");\r
-\r
-       jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);\r
-       jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");\r
-\r
-       jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object);\r
-       jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);\r
-\r
-       jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);\r
-       jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag);\r
-       jstring compName = (*env)->GetObjectField(env, typeComponent, nameField);\r
-\r
-       jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag);\r
-\r
-       PyObject *result = PyTuple_New(2);\r
-       PyTuple_SetItem(result, 0, getPythonString(env, compName));\r
-       PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding));\r
-\r
-       return result;\r
-}\r
-\r
-PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) {\r
-       jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS);\r
-       jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
-       jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";");\r
-\r
-       jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object);\r
-       jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object);\r
-\r
-       return getPythonObject(env, content, contentBinding);\r
-}\r
-\r
-PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) {\r
-       jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS);\r
-       jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS);\r
-       jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS);\r
-       jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS);\r
-       jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS);\r
-       jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS);\r
-       jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS);\r
-       jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS);\r
-       jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS);\r
-       jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS);\r
-       jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS);\r
-       jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS);\r
-       jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS);\r
-\r
-       if (value == NULL)\r
-               return Py_None;\r
-\r
-       if ((*env)->IsInstanceOf(env, binding, booleanBinding)) {\r
-               return getPythonBooleanObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, byteBinding)) {\r
-               return getPythonByteObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, integerBinding)) {\r
-               return getPythonIntegerObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, longBinding)) {\r
-               return getPythonLongObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, floatBinding)) {\r
-               return getPythonFloatObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) {\r
-               return getPythonDoubleObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, stringBinding)) {\r
-               return getPythonStringObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, recordBinding)) {\r
-               return getPythonRecordObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) {\r
-               return getPythonArrayObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, mapBinding)) {\r
-               return getPythonMapObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) {\r
-               return getPythonOptionalObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, untionBinding)) {\r
-               return getPythonUnionObject(env, value, binding);\r
-       }\r
-       else if ((*env)->IsInstanceOf(env, binding, variantBinding)) {\r
-               return getPythonVariantObject(env, value, binding);\r
-       }\r
-       else {\r
-               return Py_None;\r
-       }\r
-}\r
-\r
-void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) {\r
-       if (name && value) {\r
-               PyDict_SetItem(PyModule_GetDict(module), name, value);\r
-       }\r
-\r
-       Py_XDECREF(name);\r
-       Py_XDECREF(value);\r
-}\r
-\r
-static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {\r
-       if (d == nd) {\r
-               ncont[d] = 1;\r
-               return 1;\r
-       }\r
-       else {\r
-               npy_intp n = nContiguous(d+1, nd, strides, dims, ncont);\r
-               ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0;\r
-               return ncont[d];\r
-       }\r
-}\r
-\r
-static void copyDoubleArrayValues(JNIEnv *env, jdoubleArray array, double *data, npy_intp *offset, int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {\r
-       if (ncont[d] > 0) {\r
-               (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data);\r
-               *offset += ncont[d];\r
-       }\r
-       else {\r
-               int i;\r
-               for (i = 0; i < dims[d]; i++) {\r
-                       copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont);\r
-               }\r
-       }\r
-}\r
-\r
-jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) {\r
-       jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean");\r
-       jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;");\r
-\r
-       return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True));\r
-}\r
-\r
-jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) {\r
-       jclass longClass = (*env)->FindClass(env, "java/lang/Long");\r
-       jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;");\r
-\r
-       return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value));\r
-}\r
-\r
-jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) {\r
-       jclass doubleClass = (*env)->FindClass(env, "java/lang/Double");\r
-       jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;");\r
-\r
-       return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value));\r
-}\r
-\r
-jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) {\r
-       Py_ssize_t size = PyByteArray_Size(value);\r
-       jbyteArray result = (*env)->NewByteArray(env, (jsize)size);\r
-       char *bytes = PyByteArray_AsString(value);\r
-\r
-       (*env)->SetByteArrayRegion(env, result, 0, size, bytes);\r
-\r
-       return result;\r
-}\r
-\r
-jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) {\r
-       PyObject *utf16Value = PyUnicode_AsUTF16String(string);\r
-       Py_ssize_t len = PyBytes_Size(utf16Value) / 2;\r
-       char *bytes = PyBytes_AsString(utf16Value);\r
-\r
-       // Create Java string, skipping the byte order mark in the beginning\r
-       jstring result = (*env)->NewString(env, (jchar *)bytes + 1, (jsize)min(len, JAVA_MAXINT) - 1);\r
-\r
-       Py_XDECREF(utf16Value);\r
-\r
-       return result;\r
-}\r
-\r
-jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) {\r
-       Py_ssize_t len = PySequence_Size(seq);\r
-       jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
-       jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL);\r
-\r
-       jint i;\r
-\r
-       for (i = 0; i < jlen; i++) {\r
-               PyObject *item = PySequence_GetItem(seq, i);\r
-               if (PyUnicode_Check(item)) {\r
-                       jstring value = pythonStringAsJavaString(env, item);\r
-                       (*env)->SetObjectArrayElement(env, array, i, value);\r
-               }\r
-               else {\r
-                       throwPythonException(env, "List item not a string");\r
-                       return NULL;\r
-               }\r
-       }\r
-\r
-       return array;\r
-}\r
-\r
-jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) {\r
-       Py_ssize_t len = PySequence_Size(seq);\r
-       jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
-       jdoubleArray array = (*env)->NewDoubleArray(env, jlen);\r
-\r
-       jint i;\r
-\r
-       for (i = 0; i < jlen; i++) {\r
-               PyObject *item = PySequence_GetItem(seq, i);\r
-               if (PyFloat_Check(item)) {\r
-                       double value = PyFloat_AsDouble(item);\r
-                       (*env)->SetDoubleArrayRegion(env, array, i, 1, &value);\r
-               }\r
-               else {\r
-                       throwPythonException(env, "List item not a floating point value");\r
-                       return NULL;\r
-               }\r
-       }\r
-\r
-       return array;\r
-}\r
-\r
-jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) {\r
-       if (PyBool_Check(value))\r
-               return pythonBoolAsBooleanObject(env, value);\r
-       else if (PyLong_Check(value))\r
-               return pythonLongAsLongObject(env, value);\r
-       else if (PyFloat_Check(value))\r
-               return pythonFloatAsDoubleObject(env, value);\r
-       else if (PyUnicode_Check(value))\r
-               return pythonStringAsJavaString(env, value);\r
-       else if (PyByteArray_Check(value))\r
-               return pythonByteArrayAsByteArray(env, value);\r
-       else if (PyDict_Check(value))\r
-               return pythonDictionaryAsMap(env, value);\r
-       else if (hasNumpy && PyArray_Check(value))\r
-               return pythonArrayAsNDArray(env, (PyArrayObject *)value);\r
-       else if (PySequence_Check(value))\r
-               return pythonSequenceAsObjectArray(env, value);\r
-       else\r
-               return NULL;\r
-}\r
-\r
-jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) {\r
-       Py_ssize_t len = PySequence_Size(seq);\r
-       jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
-       jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL);\r
-\r
-       jint i;\r
-\r
-       for (i = 0; i < jlen; i++) {\r
-               PyObject *item = PySequence_GetItem(seq, i);\r
-               jobject object = pythonObjectAsObject(env, item);\r
-               (*env)->SetObjectArrayElement(env, array, i, object);\r
-       }\r
-\r
-       return array;\r
-}\r
-\r
-jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) {\r
-       Py_ssize_t len = PySequence_Size(seq);\r
-       jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
-       jbooleanArray array = (*env)->NewBooleanArray(env, jlen);\r
-\r
-       jint i;\r
-\r
-       for (i = 0; i < jlen; i++) {\r
-               PyObject *item = PySequence_GetItem(seq, i);\r
-               if (PyBool_Check(item)) {\r
-                       jboolean value = item == Py_True;\r
-                       (*env)->SetBooleanArrayRegion(env, array, i, 1, &value);\r
-               }\r
-               else {\r
-                       throwPythonException(env, "List item not a boolean");\r
-                       return NULL;\r
-               }\r
-       }\r
-\r
-       return array;\r
-}\r
-\r
-jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) {\r
-       Py_ssize_t len = PySequence_Size(seq);\r
-       jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
-       jintArray array = (*env)->NewIntArray(env, jlen);\r
-\r
-       jint i;\r
-\r
-       for (i = 0; i < jlen; i++) {\r
-               PyObject *item = PySequence_GetItem(seq, i);\r
-               if (PyLong_Check(item)) {\r
-                       jint value = PyLong_AsLong(item);\r
-                       (*env)->SetIntArrayRegion(env, array, i, 1, &value);\r
-               }\r
-               else {\r
-                       throwPythonException(env, "List item not an integer");\r
-                       return NULL;\r
-               }\r
-       }\r
-\r
-       return array;\r
-}\r
-\r
-jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) {\r
-       Py_ssize_t len = PySequence_Size(seq);\r
-       jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
-       jlongArray array = (*env)->NewLongArray(env, jlen);\r
-\r
-       jint i;\r
-\r
-       for (i = 0; i < jlen; i++) {\r
-               PyObject *item = PySequence_GetItem(seq, i);\r
-               if (PyLong_Check(item)) {\r
-                       jlong value = PyLong_AsLongLong(item);\r
-                       (*env)->SetLongArrayRegion(env, array, i, 1, &value);\r
-               }\r
-               else {\r
-                       throwPythonException(env, "List item not an integer");\r
-                       return NULL;\r
-               }\r
-       }\r
-\r
-       return array;\r
-}\r
-\r
-jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) {\r
-       jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);\r
-       jmethodID constructor = (*env)->GetMethodID(env, ndarrayClass, "<init>", "([I[D)V");\r
-\r
-       int ndims = PyArray_NDIM(array);\r
-       npy_intp *dims = PyArray_DIMS(array);\r
-\r
-       npy_intp len = PyArray_Size((PyObject*)array);\r
-       double *values = (double*)PyArray_DATA(array);\r
-\r
-       jboolean isFortran = PyArray_ISFORTRAN(array) != 0;\r
-\r
-       int i;\r
-\r
-       if (len > JAVA_MAXINT) {\r
-               throwPythonException(env, "Array too large");\r
-               return NULL;\r
-       }\r
-\r
-       {\r
-               jintArray jdims = (*env)->NewIntArray(env, ndims);\r
-               jdoubleArray jvalues = (*env)->NewDoubleArray(env, (jsize)len);\r
-\r
-               for (i = 0; i < ndims; i++) {\r
-                       jint dim = (jint)dims[i];\r
-                       (*env)->SetIntArrayRegion(env, jdims, i, 1, &dim);\r
-               }\r
-\r
-               if (PyArray_IS_C_CONTIGUOUS(array)) {\r
-                       (*env)->SetDoubleArrayRegion(env, jvalues, 0, (jsize)len, values);\r
-               }\r
-               else {\r
-                       npy_intp offset = 0;\r
-                       npy_intp *strides = PyArray_STRIDES(array);\r
-                       npy_intp *ncont = (npy_intp*)malloc((ndims + 1) * sizeof(npy_intp));\r
-                       nContiguous(0, ndims, strides, dims, ncont);\r
-                       copyDoubleArrayValues(env, jvalues, values, &offset, 0, ndims, strides, dims, ncont);\r
-                       free(ncont);\r
-               }\r
-\r
-               return (*env)->NewObject(env, ndarrayClass, constructor, jdims, jvalues, isFortran);\r
-       }\r
-}\r
-\r
-jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) {\r
-       jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap");\r
-       jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "<init>", "(I)V");\r
-       jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
-\r
-       Py_ssize_t size = PyDict_Size(dict);\r
-       jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size);\r
-\r
-       PyObject *key, *value;\r
-       Py_ssize_t pos = 0;\r
-\r
-       while (PyDict_Next(dict, &pos, &key, &value)) {\r
-               jobject keyObject = pythonObjectAsObject(env, key);\r
-               jobject valueObject = pythonObjectAsObject(env, value);\r
-               (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject);\r
-       }\r
-\r
-       return map;\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jboolean value) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = getPythonBool(value);\r
-\r
-       setPythonVariable(module, pythonName, val);\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jbooleanArray value) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = getPythonBooleanList(env, value);\r
-\r
-       setPythonVariable(module, pythonName, val);\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlong value) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = PyLong_FromLongLong(value);\r
-\r
-       setPythonVariable(module, pythonName, val);\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jintArray value) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = getPythonIntegerList(env, value);\r
-\r
-       setPythonVariable(module, pythonName, val);\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlongArray value) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = getPythonLongList(env, value);\r
-\r
-       setPythonVariable(module, pythonName, val);\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdouble value) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = PyFloat_FromDouble(value);\r
-\r
-       setPythonVariable(module, pythonName, val);\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonFloatArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jfloatArray value) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = getPythonFloatList(env, value);\r
-\r
-       setPythonVariable(module, pythonName, val);\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdoubleArray value) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = getPythonDoubleList(env, value);\r
-\r
-       setPythonVariable(module, pythonName, val);\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonStringVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jstring value) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = getPythonString(env, value);\r
-\r
-       setPythonVariable(module, pythonName, val);\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobjectArray value) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = getPythonStringList(env, value);\r
-\r
-       setPythonVariable(module, pythonName, val);\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       if (!hasNumpy) {\r
-               throwPythonException(env, "Importing numpy failed");\r
-               return;\r
-       }\r
-\r
-       {\r
-               PyObject *pythonName = getPythonString(env, variableName);\r
-               PyObject *val = getPythonNDArray(env, value);\r
-\r
-               setPythonVariable(module, pythonName, val);\r
-       }\r
-}\r
-\r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value, jobject binding) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = getPythonObject(env, value, binding);\r
-\r
-       setPythonVariable(module, pythonName, val);\r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL);\r
-\r
-       PyErr_Clear();\r
-       {\r
-               jclass sclReportingWriterClass = (*env)->FindClass(env, SCL_REPORTING_WRITER_CLASS);\r
-               jmethodID constructor = (*env)->GetMethodID(env, sclReportingWriterClass, "<init>", "()V");\r
-               jmethodID flushMethod = (*env)->GetMethodID(env, sclReportingWriterClass, "flush", "()V");\r
-\r
-               PyObject *globals;\r
-\r
-               globals = PyModule_GetDict(module);\r
-\r
-               currentEnv = env;\r
-               if (sclReportingWriterClass && constructor)\r
-                       sclWriter = (*env)->NewObject(env, sclReportingWriterClass, constructor);\r
-               else\r
-                       sclWriter = NULL;\r
-\r
-               {\r
-                       PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals);\r
-\r
-                       PyObject *exceptionType = PyErr_Occurred();\r
-                       if (exceptionType != NULL) {\r
-                               PyObject *exception, *traceback;\r
-                               PyErr_Fetch(&exceptionType, &exception, &traceback);\r
-\r
-                               {\r
-                                       PyObject *tracebackModule = PyImport_ImportModule("traceback");\r
-                                       if (tracebackModule != NULL) {\r
-                                               PyObject *formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception");\r
-                                               if (formatExc != NULL) {\r
-                                                       PyObject *args = PyTuple_Pack(3, exceptionType, exception, traceback);\r
-                                                       PyObject *message = PyObject_CallObject(formatExc, args);\r
-                                                       if (message != NULL) {\r
-                                                               PyObject *emptyStr = PyUnicode_FromString("");\r
-                                                               PyObject *joined = PyUnicode_Join(emptyStr, message);\r
-                                                               char *messageStr = PyUnicode_AsUTF8(joined);\r
-                                                               throwPythonException(env, messageStr);\r
-                                                               Py_DECREF(joined);\r
-                                                               Py_DECREF(emptyStr);\r
-                                                               Py_DECREF(message);\r
-                                                       }\r
-                                                       else {\r
-                                                               throwPythonException(env, "Internal error, no message");\r
-                                                       }\r
-                                                       Py_DECREF(args);\r
-                                                       Py_DECREF(formatExc);\r
-                                               }\r
-                                               else {\r
-                                                       throwPythonException(env, "Internal error, no format_exc function");\r
-                                               }\r
-                                               Py_DECREF(tracebackModule);\r
-                                       }\r
-                                       else {\r
-                                               throwPythonException(env, "Internal error, no traceback module");\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       (*env)->ReleaseStringUTFChars(env, statement, utfchars);\r
-\r
-                       if (sclWriter != NULL) {\r
-                               (*env)->CallVoidMethod(env, sclWriter, flushMethod);\r
-                       }\r
-\r
-                       currentEnv = NULL;\r
-                       sclWriter = NULL;\r
-\r
-                       return result != NULL ? 0 : 1;\r
-               }\r
-       }\r
-}\r
-\r
-JNIEXPORT jstring JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
-       if (value == NULL) {\r
-               throwPythonException(env, "Python variable not found");\r
-               return 0;\r
-       }\r
-\r
-       if (!PyUnicode_Check(value)) {\r
-               throwPythonException(env, "Python variable not a string");\r
-               return 0;\r
-       }\r
-\r
-       {\r
-               jstring result = pythonStringAsJavaString(env, value);\r
-               return result;\r
-       }\r
-}\r
-\r
-JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
-       if (value == NULL) {\r
-               throwPythonException(env, "Python variable not found");\r
-               return 0;\r
-       }\r
-\r
-       if (!PySequence_Check(value)) {\r
-               throwPythonException(env, "Python variable not a sequence");\r
-               return 0;\r
-       }\r
-\r
-       {\r
-               jobjectArray result = pythonSequenceAsStringArray(env, value);\r
-               return result;\r
-       }\r
-}\r
-\r
-JNIEXPORT jboolean JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
-       if (value == NULL) {\r
-               throwPythonException(env, "Python variable not found");\r
-               return 0;\r
-       }\r
-\r
-       if (!PyBool_Check(value)) {\r
-               throwPythonException(env, "Python variable not a boolean");\r
-               return 0;\r
-       }\r
-\r
-       return value == Py_True;\r
-}\r
-\r
-JNIEXPORT jbooleanArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
-       if (value == NULL) {\r
-               throwPythonException(env, "Python variable not found");\r
-               return 0;\r
-       }\r
-\r
-       if (!PySequence_Check(value)) {\r
-               throwPythonException(env, "Python variable not a sequence");\r
-               return 0;\r
-       }\r
-\r
-       {\r
-               jbooleanArray result = pythonSequenceAsBooleanArray(env, value);\r
-               return result;\r
-       }\r
-}\r
-\r
-JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
-       if (value == NULL) {\r
-               throwPythonException(env, "Python variable not found");\r
-               return 0;\r
-       }\r
-\r
-       if (!PyLong_Check(value)) {\r
-               throwPythonException(env, "Python variable not an integer");\r
-               return 0;\r
-       }\r
-\r
-       {\r
-               jlong result = PyLong_AsLongLong(value);\r
-               return result;\r
-       }\r
-}\r
-\r
-JNIEXPORT jintArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
-       if (value == NULL) {\r
-               throwPythonException(env, "Python variable not found");\r
-               return NULL;\r
-       }\r
-\r
-       if (!PySequence_Check(value)) {\r
-               throwPythonException(env, "Python variable not a sequence");\r
-               return NULL;\r
-       }\r
-\r
-       {\r
-               jintArray result = pythonSequenceAsIntegerArray(env, value);\r
-               return result;\r
-       }\r
-}\r
-\r
-JNIEXPORT jlongArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
-       if (value == NULL) {\r
-               throwPythonException(env, "Python variable not found");\r
-               return NULL;\r
-       }\r
-\r
-       if (!PySequence_Check(value)) {\r
-               throwPythonException(env, "Python variable not a sequence");\r
-               return NULL;\r
-       }\r
-\r
-       {\r
-               jlongArray result = pythonSequenceAsLongArray(env, value);\r
-               return result;\r
-       }\r
-}\r
-\r
-JNIEXPORT jdouble JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
-       if (value == NULL) {\r
-               throwPythonException(env, "Python variable not found");\r
-               return 0.0;\r
-       }\r
-\r
-       if (!PyFloat_Check(value)) {\r
-               throwPythonException(env, "Python variable not a float");\r
-               return 0.0;\r
-       }\r
-\r
-       {\r
-               jdouble result = PyFloat_AsDouble(value);\r
-               return result;\r
-       }\r
-}\r
-\r
-JNIEXPORT jdoubleArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
-       if (value == NULL) {\r
-               throwPythonException(env, "Python variable not found");\r
-               return NULL;\r
-       }\r
-\r
-       if (!PySequence_Check(value)) {\r
-               throwPythonException(env, "Python variable not a sequence");\r
-               return NULL;\r
-       }\r
-\r
-       {\r
-               jdoubleArray result = pythonSequenceAsDoubleArray(env, value);\r
-               return result;\r
-       }\r
-}\r
-\r
-JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       if (!hasNumpy) {\r
-               throwPythonException(env, "Importing numpy failed");\r
-               return NULL;\r
-       }\r
-\r
-       {\r
-               PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-               PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
-               if (value == NULL) {\r
-                       throwPythonException(env, "Python variable not found");\r
-                       return NULL;\r
-               }\r
-\r
-               if (!PyArray_Check(value)) {\r
-                       throwPythonException(env, "Python variable not an ndarray");\r
-                       return NULL;\r
-               }\r
-\r
-               if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) {\r
-                       throwPythonException(env, "Only ndarrays of type double are supported");\r
-                       return NULL;\r
-               }\r
-\r
-               {\r
-                       jobject result = pythonArrayAsNDArray(env, (PyArrayObject *)value);\r
-                       return result;\r
-               }\r
-       }\r
-}\r
-\r
-JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
-       if (value == NULL) {\r
-               throwPythonException(env, "Python variable not found");\r
-               return NULL;\r
-       }\r
-\r
-       hasNumpy = _import_array() != -1;\r
-\r
-       {\r
-               jobject result = pythonObjectAsObject(env, value);\r
-               return result;\r
-       }\r
-}\r
-\r
-JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
-       PyObject *module = getModule(contextID);\r
-       PyObject *dict = PyModule_GetDict(module);\r
-\r
-       PyObject *pythonName = getPythonString(env, variableName);\r
-\r
-       if (!PyDict_Contains(dict, pythonName)) {\r
-               return 0;\r
-       }\r
-\r
-       {\r
-               PyObject *value = PyDict_GetItem(dict, pythonName);\r
-\r
-               jint result;\r
-\r
-               if (PyBool_Check(value))\r
-                       result = 1;\r
-               else if (PyLong_Check(value))\r
-                       result = 2;\r
-               else if (PyFloat_Check(value))\r
-                       result = 3;\r
-               else if (PyUnicode_Check(value))\r
-                       result = 4;\r
-               else if (PyByteArray_Check(value))\r
-                       result = 5;\r
-               else if (PyDict_Check(value))\r
-                       result = 6;\r
-               else if (hasNumpy && PyArray_Check(value))\r
-                       result = 7;\r
-               else if (PySequence_Check(value))\r
-                       result = 8;\r
-               else\r
-                       result = -1;\r
-\r
-               return result;\r
-       }\r
-}\r
-\r
-JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(JNIEnv *env, jobject thisObj, jlong contextID) {\r
-       PyObject *module = getModule(contextID);\r
-       PyObject *dict = PyModule_GetDict(module);\r
-\r
-       PyObject *keys = PyDict_Keys(dict);\r
-       Py_ssize_t size = PyList_Size(keys);\r
-\r
-       jobjectArray result = (*env)->NewObjectArray(env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL);\r
-\r
-       Py_ssize_t i;\r
-       for (i = 0; i < size; i++) {\r
-               jstring javaName = pythonStringAsJavaString(env, PyList_GetItem(keys, i));\r
-               (*env)->SetObjectArrayElement(env, result, (jint)i, javaName);\r
-       }\r
-\r
-       Py_XDECREF(keys);\r
-\r
-       return result;\r
-}\r
-\r
-BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)\r
-//extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)\r
-{\r
-    switch (fdwReason)\r
-    {\r
-        case DLL_PROCESS_ATTACH:\r
-            // attach to process\r
-            // return FALSE to fail DLL load\r
-            break;\r
-\r
-        case DLL_PROCESS_DETACH:\r
-            // detach from process\r
-            break;\r
-\r
-        case DLL_THREAD_ATTACH:\r
-            // attach to thread\r
-            break;\r
-\r
-        case DLL_THREAD_DETACH:\r
-            // detach from thread\r
-            break;\r
-    }\r
-    return TRUE; // succesful\r
-}\r
+///////////////////////////////////////////////////////
+//                                                   //
+//   VTT Technical Research Centre of Finland LTD    //
+//   For internal use only. Do not redistribute.     //
+//                                                   //
+//   Authors:                                        //
+//       Antton Tapani    ext-antton.tapani@vtt.fi   //
+//                                                   //
+//   Last modified by Antton Tapani    9.2016        //
+//                                                   //
+///////////////////////////////////////////////////////
+
+#include "sclpy.h"
+
+#include <windows.h>
+
+jint throwException( JNIEnv *env, char *className, const char *message )
+{
+    jclass exClass = (*env)->FindClass( env, className);
+    if (exClass == NULL) {
+        return 0;
+    }
+
+    return (*env)->ThrowNew( env, exClass, message );
+}
+
+jint throwPythonException( JNIEnv *env, const char *message ) {
+       return throwException( env, PYTHON_EXCEPTION, message );
+}
+
+jint throwIllegalArgumentException( JNIEnv *env, const char *message ) {
+       return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message );
+}
+
+PyObject* getModule(jlong contextID) {
+       return PyState_FindModule((PyModuleDef*) contextID);
+//     return PyImport_AddModule("__main__");
+}
+
+int moduleCount = 0;
+int hasNumpy = 0;
+PyThreadState *main_ts = 0;
+
+static JNIEnv *currentEnv = NULL;
+jobject sclWriter = NULL;
+
+static PyObject *
+writeToSCL(PyObject *self, PyObject *args)
+{
+    if (currentEnv != NULL && sclWriter != NULL) {
+       JNIEnv *env = currentEnv;
+
+               Py_UNICODE *what;
+               Py_ssize_t length;
+               if (!PyArg_ParseTuple(args, "u#", &what, &length))
+                       return Py_BuildValue("");
+
+               {
+               jclass writerClass = (*env)->FindClass(env, WRITER_CLASS);
+               jmethodID writeMethod = (*env)->GetMethodID(env, writerClass, "write", "([CII)V");
+               jcharArray chars = (*env)->NewCharArray(env, (jsize)length);
+
+               (*env)->SetCharArrayRegion(env, chars, 0, length, what);
+               (*env)->CallVoidMethod(env, sclWriter, writeMethod, chars, 0, length);
+               }
+    }
+
+    return Py_BuildValue("");
+}
+
+static PyMethodDef sclWriterMethods[] = {
+    {"write", writeToSCL, METH_VARARGS, "Write something."},
+    {NULL, NULL, 0, NULL}
+};
+
+
+JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) {
+       char name[16];
+
+       if (!main_ts) {
+        Py_Initialize();
+
+        {
+               static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods, };
+                       PyObject *m = PyModule_Create(&moduledef);
+
+               if (m == NULL) throwException(env, PYTHON_EXCEPTION, "Failed to create SCL writer module");
+                       PySys_SetObject("stdout", m);
+                       PySys_SetObject("stderr", m);
+        }
+
+       hasNumpy = _import_array();
+       hasNumpy = hasNumpy != -1;
+       main_ts = PyEval_SaveThread();
+       }
+
+       sprintf(name, "SCL_%d", ++moduleCount);
+
+       PyEval_RestoreThread(main_ts);
+       {
+               PyObject *module;
+               PyModuleDef *modDef = malloc(sizeof(PyModuleDef));
+               memset(modDef, 0, sizeof(PyModuleDef));
+               modDef->m_name = strdup(name);
+               modDef->m_doc = NULL;
+               modDef->m_size = -1;
+
+               module = PyModule_Create(modDef);
+               Py_INCREF(module);
+               PyState_AddModule(module, modDef);
+
+               {
+                       PyObject *builtin = PyImport_AddModule("builtins");
+                       PyObject *dict = PyModule_GetDict(module);
+                       PyDict_SetItemString(dict, "__builtin__", builtin);
+                       PyDict_SetItemString(dict, "__builtins__", builtin);
+
+                       return (jlong)modDef;
+               }
+       }
+}
+
+JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) {
+       PyModuleDef *modDef = (PyModuleDef*)contextID;
+       PyObject *module;
+       PyEval_RestoreThread(main_ts);
+       module = PyState_FindModule(modDef);
+       Py_XDECREF(module);
+       PyState_RemoveModule(modDef);
+       free((char*)modDef->m_name);
+       free(modDef);
+       PyEval_SaveThread();
+}
+
+PyObject *getPythonBool(jboolean value) {
+       if (value) {
+               Py_RETURN_TRUE;
+       }
+       else {
+               Py_RETURN_FALSE;
+       }
+}
+
+PyObject *getPythonString(JNIEnv *env, jstring string) {
+       jsize len = (*env)->GetStringLength(env, string);
+       const jchar *chars = (*env)->GetStringChars(env, string, NULL);
+
+       PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
+
+       (*env)->ReleaseStringChars(env, string, chars);
+       return value;
+}
+
+PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) {
+       jsize nitems = (*env)->GetArrayLength(env, value);
+       jint *values = (*env)->GetIntArrayElements(env, value, NULL);
+       jclass stringClass = (*env)->FindClass(env, STRING_CLASS);
+       jint i;
+
+       PyObject *result = PyList_New(nitems);
+       for (i = 0; i < nitems; i++) {
+               jobject item = (*env)->GetObjectArrayElement(env, value, i);
+               if (item != NULL && (*env)->IsInstanceOf(env, item, stringClass)) {
+                       PyList_SetItem(result, i, getPythonString(env, (jstring)item));
+               }
+               else {
+                       PyList_SetItem(result, i, Py_None);
+               }
+       }
+
+       (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
+       return result;
+}
+
+PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) {
+       jsize nitems = (*env)->GetArrayLength(env, value);
+       jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL);
+       jint i;
+
+       PyObject *result = PyList_New(nitems);
+       for (i = 0; i < nitems; i++) {
+               PyList_SetItem(result, i, getPythonBool(values[i]));
+       }
+
+       (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT);
+       return result;
+}
+
+PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) {
+       jint len = (*env)->GetArrayLength(env, value);
+       jbyte *values = (*env)->GetByteArrayElements(env, value, NULL);
+
+       PyObject *result = PyByteArray_FromStringAndSize(values, len);
+
+       (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT);
+       return result;
+}
+
+PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) {
+       jsize nitems = (*env)->GetArrayLength(env, value);
+       jint *values = (*env)->GetIntArrayElements(env, value, NULL);
+       jint i;
+
+       PyObject *result = PyList_New(nitems);
+       for (i = 0; i < nitems; i++) {
+               PyList_SetItem(result, i, PyLong_FromLong(values[i]));
+       }
+
+       (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
+       return result;
+}
+
+PyObject *getPythonLongList(JNIEnv *env, jlongArray value) {
+       jsize nitems = (*env)->GetArrayLength(env, value);
+       jlong *values = (*env)->GetLongArrayElements(env, value, NULL);
+       jint i;
+
+       PyObject *result = PyList_New(nitems);
+       for (i = 0; i < nitems; i++) {
+               PyList_SetItem(result, i, PyLong_FromLongLong(values[i]));
+       }
+
+       (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT);
+       return result;
+}
+
+PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) {
+       jsize nitems = (*env)->GetArrayLength(env, value);
+       float *values = (*env)->GetFloatArrayElements(env, value, NULL);
+       jint i;
+
+       PyObject *result = PyList_New(nitems);
+       for (i = 0; i < nitems; i++) {
+               PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i]));
+       }
+
+       (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT);
+       return result;
+}
+
+PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) {
+       jsize nitems = (*env)->GetArrayLength(env, value);
+       double *values = (*env)->GetDoubleArrayElements(env, value, NULL);
+       jint i;
+
+       PyObject *result = PyList_New(nitems);
+       for (i = 0; i < nitems; i++) {
+               PyList_SetItem(result, i, PyFloat_FromDouble(values[i]));
+       }
+
+       (*env)->ReleaseDoubleArrayElements(env, value, values, JNI_ABORT);
+       return result;
+}
+
+PyObject *getPythonNDArray(JNIEnv *env, jobject value) {
+       jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
+       jmethodID dimsMethod = (*env)->GetMethodID(env, ndarrayClass, "dims", "()[I");
+       jmethodID getValuesMethod = (*env)->GetMethodID(env, ndarrayClass, "getValues", "()[D");
+
+       jintArray jdims = (*env)->CallObjectMethod(env, value, dimsMethod);
+       jsize ndims = (*env)->GetArrayLength(env, jdims);
+       jint *dims = (*env)->GetIntArrayElements(env, jdims, NULL);
+
+       jdoubleArray jvalues = (*env)->CallObjectMethod(env, value, getValuesMethod);
+       jsize len = (*env)->GetArrayLength(env, jvalues);
+       jdouble *values = (*env)->GetDoubleArrayElements(env, jvalues, NULL);
+
+       npy_intp *pyDims = (npy_intp*)malloc(ndims * sizeof(npy_intp));
+
+       jint i, nelem = ndims > 0 ? 1 : 0;
+       for (i = 0; i < ndims; i++) {
+               nelem *= dims[i];
+               pyDims[i] = dims[i];
+       }
+
+       len = min(len, nelem);
+
+       {
+               PyObject *array = PyArray_EMPTY(ndims, pyDims, NPY_DOUBLE, 0);
+               double *data = (double *)PyArray_DATA((PyArrayObject*)array);
+
+               memcpy(data, values, len * sizeof(double));
+
+               free(pyDims);
+
+               (*env)->ReleaseDoubleArrayElements(env, jvalues, values, JNI_ABORT);
+               (*env)->ReleaseIntArrayElements(env, jdims, dims, JNI_ABORT);
+
+               return array;
+       }
+}
+
+PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z");
+
+       jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object);
+       return getPythonBool(bvalue);
+}
+
+PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS);
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B");
+
+       jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object);
+       return PyLong_FromLong(v);
+}
+
+PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS);
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I");
+
+       jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object);
+       return PyLong_FromLong(v);
+}
+
+PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS);
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J");
+
+       jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object);
+       return PyLong_FromLongLong(v);
+}
+
+PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS);
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F");
+
+       jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object);
+       return PyFloat_FromDouble(v);
+}
+
+PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D");
+
+       jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object);
+       return PyFloat_FromDouble(v);
+}
+
+PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS);
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";");
+
+       jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
+       jsize len = (*env)->GetStringLength(env, string);
+       const jchar *chars = (*env)->GetStringChars(env, string, NULL);
+
+       PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
+
+       (*env)->ReleaseStringChars(env, string, chars);
+       return value;
+}
+
+PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS);
+       jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
+       jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
+       jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
+
+       jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS);
+       jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";");
+       jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I");
+
+       jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
+       jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
+
+       jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
+       jint n = (*env)->CallIntMethod(env, type, getComponentCount);
+       jint i;
+
+       PyObject *result = PyDict_New();
+       for (i = 0; i < n; i++) {
+               jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i);
+               jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField);
+               jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i);
+               jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i);
+
+               PyObject *item = getPythonObject(env, componentObject, componentBinding);
+               PyDict_SetItem(result, getPythonString(env, fieldName), item);
+       }
+
+       return result;
+}
+
+PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS);
+       jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
+       jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
+       jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
+
+       jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
+
+       jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
+
+       PyObject *result = PyList_New(size);
+
+       jint i;
+       for (i = 0; i < size; i++) {
+               jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i);
+               if (item != NULL)
+                       PyList_SetItem(result, i, getPythonObject(env, item, componentBinding));
+               else
+                       PyList_SetItem(result, i, Py_None);
+       }
+
+       return result;
+}
+
+PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS);
+       jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS);
+       jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";");
+       jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";");
+       jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
+       jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V");
+
+       jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod);
+       jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod);
+
+       jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
+       jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL);
+       jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL);
+
+       PyObject *result = PyDict_New();
+       jint i;
+
+       (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values);
+
+       for (i = 0; i < size; i++) {
+               jobject key = (*env)->GetObjectArrayElement(env, keys, i);
+               jobject item = (*env)->GetObjectArrayElement(env, values, i);
+               PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding));
+       }
+
+       (*env)->DeleteLocalRef(env, keys);
+       (*env)->DeleteLocalRef(env, values);
+
+       return result;
+}
+
+PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
+       jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z");
+
+       jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object);
+
+       if (hasValue) {
+               jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
+               jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
+
+               jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
+               jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
+
+               return getPythonObject(env, value, componentBinding);
+       }
+       else {
+               return Py_None;
+       }
+}
+
+PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS);
+       jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
+       jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I");
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
+       jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
+
+       jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS);
+       jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";");
+
+       jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
+       jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
+
+       jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object);
+       jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
+
+       jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
+       jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag);
+       jstring compName = (*env)->GetObjectField(env, typeComponent, nameField);
+
+       jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag);
+
+       PyObject *result = PyTuple_New(2);
+       PyTuple_SetItem(result, 0, getPythonString(env, compName));
+       PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding));
+
+       return result;
+}
+
+PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) {
+       jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS);
+       jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
+       jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";");
+
+       jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object);
+       jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object);
+
+       return getPythonObject(env, content, contentBinding);
+}
+
+PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) {
+       jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
+       jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS);
+       jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS);
+       jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS);
+       jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS);
+       jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
+       jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS);
+       jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS);
+       jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS);
+       jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS);
+       jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
+       jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS);
+       jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS);
+
+       if (value == NULL)
+               return Py_None;
+
+       if ((*env)->IsInstanceOf(env, binding, booleanBinding)) {
+               return getPythonBooleanObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, byteBinding)) {
+               return getPythonByteObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, integerBinding)) {
+               return getPythonIntegerObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, longBinding)) {
+               return getPythonLongObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, floatBinding)) {
+               return getPythonFloatObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) {
+               return getPythonDoubleObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, stringBinding)) {
+               return getPythonStringObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, recordBinding)) {
+               return getPythonRecordObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) {
+               return getPythonArrayObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, mapBinding)) {
+               return getPythonMapObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) {
+               return getPythonOptionalObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, untionBinding)) {
+               return getPythonUnionObject(env, value, binding);
+       }
+       else if ((*env)->IsInstanceOf(env, binding, variantBinding)) {
+               return getPythonVariantObject(env, value, binding);
+       }
+       else {
+               return Py_None;
+       }
+}
+
+void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) {
+       if (name && value) {
+               PyDict_SetItem(PyModule_GetDict(module), name, value);
+       }
+
+       Py_XDECREF(name);
+       Py_XDECREF(value);
+}
+
+static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {
+       if (d == nd) {
+               ncont[d] = 1;
+               return 1;
+       }
+       else {
+               npy_intp n = nContiguous(d+1, nd, strides, dims, ncont);
+               ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0;
+               return ncont[d];
+       }
+}
+
+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) {
+       if (ncont[d] > 0) {
+               (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data);
+               *offset += ncont[d];
+       }
+       else {
+               int i;
+               for (i = 0; i < dims[d]; i++) {
+                       copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont);
+               }
+       }
+}
+
+jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) {
+       jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean");
+       jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;");
+
+       return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True));
+}
+
+jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) {
+       jclass longClass = (*env)->FindClass(env, "java/lang/Long");
+       jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;");
+
+       return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value));
+}
+
+jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) {
+       jclass doubleClass = (*env)->FindClass(env, "java/lang/Double");
+       jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;");
+
+       return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value));
+}
+
+jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) {
+       Py_ssize_t size = PyByteArray_Size(value);
+       jbyteArray result = (*env)->NewByteArray(env, (jsize)size);
+       char *bytes = PyByteArray_AsString(value);
+
+       (*env)->SetByteArrayRegion(env, result, 0, size, bytes);
+
+       return result;
+}
+
+jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) {
+       PyObject *utf16Value = PyUnicode_AsUTF16String(string);
+       Py_ssize_t len = PyBytes_Size(utf16Value) / 2;
+       char *bytes = PyBytes_AsString(utf16Value);
+
+       // Create Java string, skipping the byte order mark in the beginning
+       jstring result = (*env)->NewString(env, (jchar *)bytes + 1, (jsize)min(len, JAVA_MAXINT) - 1);
+
+       Py_XDECREF(utf16Value);
+
+       return result;
+}
+
+jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) {
+       Py_ssize_t len = PySequence_Size(seq);
+       jsize jlen = (jsize)min(len, JAVA_MAXINT);
+       jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL);
+
+       jint i;
+
+       for (i = 0; i < jlen; i++) {
+               PyObject *item = PySequence_GetItem(seq, i);
+               if (PyUnicode_Check(item)) {
+                       jstring value = pythonStringAsJavaString(env, item);
+                       (*env)->SetObjectArrayElement(env, array, i, value);
+               }
+               else {
+                       throwPythonException(env, "List item not a string");
+                       return NULL;
+               }
+       }
+
+       return array;
+}
+
+jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) {
+       Py_ssize_t len = PySequence_Size(seq);
+       jsize jlen = (jsize)min(len, JAVA_MAXINT);
+       jdoubleArray array = (*env)->NewDoubleArray(env, jlen);
+
+       jint i;
+
+       for (i = 0; i < jlen; i++) {
+               PyObject *item = PySequence_GetItem(seq, i);
+               if (PyFloat_Check(item)) {
+                       double value = PyFloat_AsDouble(item);
+                       (*env)->SetDoubleArrayRegion(env, array, i, 1, &value);
+               }
+               else {
+                       throwPythonException(env, "List item not a floating point value");
+                       return NULL;
+               }
+       }
+
+       return array;
+}
+
+jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) {
+       if (PyBool_Check(value))
+               return pythonBoolAsBooleanObject(env, value);
+       else if (PyLong_Check(value))
+               return pythonLongAsLongObject(env, value);
+       else if (PyFloat_Check(value))
+               return pythonFloatAsDoubleObject(env, value);
+       else if (PyUnicode_Check(value))
+               return pythonStringAsJavaString(env, value);
+       else if (PyByteArray_Check(value))
+               return pythonByteArrayAsByteArray(env, value);
+       else if (PyDict_Check(value))
+               return pythonDictionaryAsMap(env, value);
+       else if (hasNumpy && PyArray_Check(value))
+               return pythonArrayAsNDArray(env, (PyArrayObject *)value);
+       else if (PySequence_Check(value))
+               return pythonSequenceAsObjectArray(env, value);
+       else
+               return NULL;
+}
+
+jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) {
+       Py_ssize_t len = PySequence_Size(seq);
+       jsize jlen = (jsize)min(len, JAVA_MAXINT);
+       jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL);
+
+       jint i;
+
+       for (i = 0; i < jlen; i++) {
+               PyObject *item = PySequence_GetItem(seq, i);
+               jobject object = pythonObjectAsObject(env, item);
+               (*env)->SetObjectArrayElement(env, array, i, object);
+       }
+
+       return array;
+}
+
+jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) {
+       Py_ssize_t len = PySequence_Size(seq);
+       jsize jlen = (jsize)min(len, JAVA_MAXINT);
+       jbooleanArray array = (*env)->NewBooleanArray(env, jlen);
+
+       jint i;
+
+       for (i = 0; i < jlen; i++) {
+               PyObject *item = PySequence_GetItem(seq, i);
+               if (PyBool_Check(item)) {
+                       jboolean value = item == Py_True;
+                       (*env)->SetBooleanArrayRegion(env, array, i, 1, &value);
+               }
+               else {
+                       throwPythonException(env, "List item not a boolean");
+                       return NULL;
+               }
+       }
+
+       return array;
+}
+
+jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) {
+       Py_ssize_t len = PySequence_Size(seq);
+       jsize jlen = (jsize)min(len, JAVA_MAXINT);
+       jintArray array = (*env)->NewIntArray(env, jlen);
+
+       jint i;
+
+       for (i = 0; i < jlen; i++) {
+               PyObject *item = PySequence_GetItem(seq, i);
+               if (PyLong_Check(item)) {
+                       jint value = PyLong_AsLong(item);
+                       (*env)->SetIntArrayRegion(env, array, i, 1, &value);
+               }
+               else {
+                       throwPythonException(env, "List item not an integer");
+                       return NULL;
+               }
+       }
+
+       return array;
+}
+
+jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) {
+       Py_ssize_t len = PySequence_Size(seq);
+       jsize jlen = (jsize)min(len, JAVA_MAXINT);
+       jlongArray array = (*env)->NewLongArray(env, jlen);
+
+       jint i;
+
+       for (i = 0; i < jlen; i++) {
+               PyObject *item = PySequence_GetItem(seq, i);
+               if (PyLong_Check(item)) {
+                       jlong value = PyLong_AsLongLong(item);
+                       (*env)->SetLongArrayRegion(env, array, i, 1, &value);
+               }
+               else {
+                       throwPythonException(env, "List item not an integer");
+                       return NULL;
+               }
+       }
+
+       return array;
+}
+
+jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) {
+       jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
+       jmethodID constructor = (*env)->GetMethodID(env, ndarrayClass, "<init>", "([I[D)V");
+
+       int ndims = PyArray_NDIM(array);
+       npy_intp *dims = PyArray_DIMS(array);
+
+       npy_intp len = PyArray_Size((PyObject*)array);
+       double *values = (double*)PyArray_DATA(array);
+
+       jboolean isFortran = PyArray_ISFORTRAN(array) != 0;
+
+       int i;
+
+       if (len > JAVA_MAXINT) {
+               throwPythonException(env, "Array too large");
+               return NULL;
+       }
+
+       {
+               jintArray jdims = (*env)->NewIntArray(env, ndims);
+               jdoubleArray jvalues = (*env)->NewDoubleArray(env, (jsize)len);
+
+               for (i = 0; i < ndims; i++) {
+                       jint dim = (jint)dims[i];
+                       (*env)->SetIntArrayRegion(env, jdims, i, 1, &dim);
+               }
+
+               if (PyArray_IS_C_CONTIGUOUS(array)) {
+                       (*env)->SetDoubleArrayRegion(env, jvalues, 0, (jsize)len, values);
+               }
+               else {
+                       npy_intp offset = 0;
+                       npy_intp *strides = PyArray_STRIDES(array);
+                       npy_intp *ncont = (npy_intp*)malloc((ndims + 1) * sizeof(npy_intp));
+                       nContiguous(0, ndims, strides, dims, ncont);
+                       copyDoubleArrayValues(env, jvalues, values, &offset, 0, ndims, strides, dims, ncont);
+                       free(ncont);
+               }
+
+               return (*env)->NewObject(env, ndarrayClass, constructor, jdims, jvalues, isFortran);
+       }
+}
+
+jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) {
+       jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap");
+       jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "<init>", "(I)V");
+       jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
+
+       Py_ssize_t size = PyDict_Size(dict);
+       jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size);
+
+       PyObject *key, *value;
+       Py_ssize_t pos = 0;
+
+       while (PyDict_Next(dict, &pos, &key, &value)) {
+               jobject keyObject = pythonObjectAsObject(env, key);
+               jobject valueObject = pythonObjectAsObject(env, value);
+               (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject);
+       }
+
+       return map;
+}
+
+#define DEF_SETTER(typename, jtype, j2py)                               \
+    JNIEXPORT void JNICALL                                              \
+    Java_org_simantics_pythonlink_PythonContext_setPython##typename     \
+    ##VariableImpl(                                                     \
+        JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, \
+        jtype value) {                                                  \
+            PyObject *module = getModule(contextID);                    \
+                                                                        \
+            PyEval_RestoreThread(main_ts);                              \
+            setPythonVariable(module, getPythonString(env, variableName), \
+                              j2py(env, value));                        \
+            PyEval_SaveThread();                                        \
+    }
+
+#define getPythonBoolean(env, value) getPythonBool(value)
+#define getPythonLong(env, value) PyLong_FromLongLong(value)
+#define getPythonDouble(env, value) PyFloat_FromDouble(value)
+
+DEF_SETTER(Boolean, jboolean, getPythonBoolean)
+DEF_SETTER(BooleanArray, jbooleanArray, getPythonBooleanList)
+DEF_SETTER(Long, jlong, getPythonLong)
+DEF_SETTER(IntegerArray, jintArray, getPythonIntegerList)
+DEF_SETTER(LongArray, jlongArray, getPythonLongList)
+DEF_SETTER(Double, jdouble, getPythonDouble)
+DEF_SETTER(FloatArray, jfloatArray, getPythonFloatList)
+DEF_SETTER(DoubleArray, jdoubleArray, getPythonDoubleList)
+DEF_SETTER(String, jstring, getPythonString)
+DEF_SETTER(StringArray, jobjectArray, getPythonStringList)
+
+JNIEXPORT void JNICALL
+Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl(
+               JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
+               jobject value) {
+       PyObject *module = getModule(contextID);
+
+       if (!hasNumpy) {
+               throwPythonException(env, "Importing numpy failed");
+               return;
+       }
+
+       PyEval_RestoreThread(main_ts);
+       {
+               PyObject *pythonName = getPythonString(env, variableName);
+               PyObject *val = getPythonNDArray(env, value);
+
+               setPythonVariable(module, pythonName, val);
+       }
+       PyEval_SaveThread();
+}
+
+JNIEXPORT void JNICALL
+Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(
+               JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
+               jobject value, jobject binding) {
+       PyObject *module = getModule(contextID);
+
+       PyEval_RestoreThread(main_ts);
+       setPythonVariable(module, getPythonString(env, variableName),
+                                         getPythonObject(env, value, binding));
+       PyEval_SaveThread();
+}
+
+JNIEXPORT jint JNICALL
+Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(
+               JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) {
+       PyObject *module = getModule(contextID);
+
+       const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL);
+
+       PyEval_RestoreThread(main_ts);
+       PyErr_Clear();
+       {
+               jclass sclReportingWriterClass = (*env)->FindClass(env, SCL_REPORTING_WRITER_CLASS);
+               jmethodID constructor = (*env)->GetMethodID(env, sclReportingWriterClass, "<init>", "()V");
+               jmethodID flushMethod = (*env)->GetMethodID(env, sclReportingWriterClass, "flush", "()V");
+
+               PyObject *globals;
+
+               globals = PyModule_GetDict(module);
+
+               currentEnv = env;
+               if (sclReportingWriterClass && constructor)
+                       sclWriter = (*env)->NewObject(env, sclReportingWriterClass, constructor);
+               else
+                       sclWriter = NULL;
+
+               {
+                       PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals);
+
+                       PyObject *exceptionType = PyErr_Occurred();
+                       if (exceptionType != NULL) {
+                               PyObject *exception, *traceback;
+                               PyErr_Fetch(&exceptionType, &exception, &traceback);
+
+                               {
+                                       PyObject *tracebackModule = PyImport_ImportModule("traceback");
+                                       if (tracebackModule != NULL) {
+                                               PyObject *formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception");
+                                               if (formatExc != NULL) {
+                                                       PyObject *args = PyTuple_Pack(3, exceptionType, exception, traceback);
+                                                       PyObject *message = PyObject_CallObject(formatExc, args);
+                                                       if (message != NULL) {
+                                                               PyObject *emptyStr = PyUnicode_FromString("");
+                                                               PyObject *joined = PyUnicode_Join(emptyStr, message);
+                                                               char *messageStr = PyUnicode_AsUTF8(joined);
+                                                               throwPythonException(env, messageStr);
+                                                               Py_DECREF(joined);
+                                                               Py_DECREF(emptyStr);
+                                                               Py_DECREF(message);
+                                                       }
+                                                       else {
+                                                               PyTypeObject
+                                                                       *ty = (PyTypeObject *)exceptionType;
+                                                               throwPythonException(
+                                                                               env, ty ? ty->tp_name
+                                                                                               : "Internal error, null exception type");
+                                                       }
+                                                       Py_DECREF(args);
+                                                       Py_DECREF(formatExc);
+                                               }
+                                               else {
+                                                       throwPythonException(env, "Internal error, no format_exc function");
+                                               }
+                                               Py_DECREF(tracebackModule);
+                                       }
+                                       else {
+                                               throwPythonException(env, "Internal error, no traceback module");
+                                       }
+                               }
+                               Py_XDECREF(exceptionType);
+                               Py_XDECREF(exception);
+                               Py_XDECREF(traceback);
+                       }
+
+                       PyEval_SaveThread();
+                       (*env)->ReleaseStringUTFChars(env, statement, utfchars);
+
+                       if (sclWriter != NULL) {
+                               (*env)->CallVoidMethod(env, sclWriter, flushMethod);
+                       }
+
+                       currentEnv = NULL;
+                       sclWriter = NULL;
+
+                       return result != NULL ? 0 : 1;
+               }
+       }
+}
+
+// Returns a borrowed reference.
+static PyObject *getPythonValue(
+               JNIEnv *env, jlong contextID, jstring variableName) {
+       PyObject *module = getModule(contextID);
+    PyObject *pythonName = getPythonString(env, variableName);
+    PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);
+
+    Py_DECREF(pythonName);
+    if (value == NULL) {
+        throwPythonException(env, "Python variable not found");
+    }
+    return value;
+}
+
+#define DEF_GETTER(typename, jtype, check, desc, py2j)                  \
+    JNIEXPORT jtype JNICALL                                             \
+    Java_org_simantics_pythonlink_PythonContext_getPython##typename     \
+    ##VariableImpl(                                                     \
+            JNIEnv *env, jobject thisObj, jlong contextID,              \
+            jstring variableName) {                                     \
+        jtype result = 0;                                               \
+        PyEval_RestoreThread(main_ts);                                  \
+        do {                                                            \
+            PyObject *value = getPythonValue(env, contextID, variableName); \
+            if (value == 0) break;                                      \
+            if (check(value)) {                                         \
+                result = py2j(env, value);                              \
+            } else {                                                    \
+                throwPythonException(env, "Python variable not " desc); \
+            }                                                           \
+        } while (0);                                                    \
+        PyEval_SaveThread();                                            \
+        return result;                                                  \
+    }
+
+#define pythonBoolAsJboolean(env, value) ((value) == Py_True)
+#define pythonLongAsJlong(env, value) PyLong_AsLongLong(value)
+#define pythonFloatAsJdouble(env, value) PyFloat_AsDouble(value)
+
+DEF_GETTER(String, jstring, PyUnicode_Check, "a string",
+                  pythonStringAsJavaString)
+DEF_GETTER(StringArray, jobjectArray, PySequence_Check, "a sequence",
+                  pythonSequenceAsStringArray)
+DEF_GETTER(Boolean, jboolean, PyBool_Check, "a Boolean", pythonBoolAsJboolean)
+DEF_GETTER(BooleanArray, jbooleanArray, PySequence_Check, "a sequence",
+                  pythonSequenceAsBooleanArray)
+DEF_GETTER(Long, jlong, PyLong_Check, "an integer", pythonLongAsJlong)
+DEF_GETTER(IntegerArray, jintArray, PySequence_Check, "a sequence",
+                  pythonSequenceAsIntegerArray)
+DEF_GETTER(LongArray, jlongArray, PySequence_Check, "a sequence",
+                  pythonSequenceAsLongArray)
+DEF_GETTER(Double, jdouble, PyFloat_Check, "a float", pythonFloatAsJdouble)
+DEF_GETTER(DoubleArray, jdoubleArray, PySequence_Check, "a sequence",
+                  pythonSequenceAsDoubleArray)
+
+JNIEXPORT jobject JNICALL
+Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(
+               JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
+       jobject result = NULL;
+
+       if (!hasNumpy) {
+               throwPythonException(env, "Importing numpy failed");
+               return NULL;
+       }
+
+       PyEval_RestoreThread(main_ts);
+       do {
+               PyObject *value = getPythonValue(env, contextID, variableName);
+               if (value == NULL) break;
+               if (!PyArray_Check(value)) {
+                       throwPythonException(env, "Python variable not an ndarray");
+               } else if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) {
+                       throwPythonException(
+                                       env, "Only ndarrays of type double are supported");
+               } else {
+                       result = pythonArrayAsNDArray(env, (PyArrayObject *)value);
+               }
+       } while (0);
+       PyEval_SaveThread();
+       return result;
+}
+
+#define python_anything_goes(value) 1
+
+DEF_GETTER(Variant, jobject, python_anything_goes, "frabjous",
+                  pythonObjectAsObject)
+
+JNIEXPORT jint JNICALL
+Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(
+               JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
+       jint result = 0;
+       PyEval_RestoreThread(main_ts);
+       {
+               PyObject *value = getPythonValue(env, contextID, variableName);
+               if (PyBool_Check(value))
+                       result = 1;
+               else if (PyLong_Check(value))
+                       result = 2;
+               else if (PyFloat_Check(value))
+                       result = 3;
+               else if (PyUnicode_Check(value))
+                       result = 4;
+               else if (PyByteArray_Check(value))
+                       result = 5;
+               else if (PyDict_Check(value))
+                       result = 6;
+               else if (hasNumpy && PyArray_Check(value))
+                       result = 7;
+               else if (PySequence_Check(value))
+                       result = 8;
+               else
+                       result = -1;
+       }
+       PyEval_SaveThread();
+       return result;
+}
+
+JNIEXPORT jobjectArray JNICALL
+Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(
+               JNIEnv *env, jobject thisObj, jlong contextID) {
+       jobjectArray result = NULL;
+       PyEval_RestoreThread(main_ts);
+       {
+               PyObject *module = getModule(contextID);
+               PyObject *dict = PyModule_GetDict(module);
+
+               PyObject *keys = PyDict_Keys(dict);
+               Py_ssize_t size = PyList_Size(keys);
+               Py_ssize_t i;
+
+               result = (*env)->NewObjectArray(
+                               env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL);
+
+               for (i = 0; i < size; i++) {
+                       jstring javaName = pythonStringAsJavaString(
+                                       env, PyList_GetItem(keys, i));
+                       (*env)->SetObjectArrayElement(env, result, (jint)i, javaName);
+               }
+
+               Py_XDECREF(keys);
+       }
+       PyEval_SaveThread();
+       return result;
+}
+
+BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+//extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+    switch (fdwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+            // attach to process
+            // return FALSE to fail DLL load
+            break;
+
+        case DLL_PROCESS_DETACH:
+            // detach from process
+            break;
+
+        case DLL_THREAD_ATTACH:
+            // attach to thread
+            break;
+
+        case DLL_THREAD_DETACH:
+            // detach from thread
+            break;
+    }
+    return TRUE; // succesful
+}