From: Reino Ruusu Date: Wed, 1 Feb 2017 15:32:43 +0000 (+0200) Subject: Merge branch 'change/300/2' X-Git-Tag: v1.31.0~6 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fpython.git;a=commitdiff_plain;h=ac16ebed6a3e0932f774ca3ee5963ed776ef6c08 Merge branch 'change/300/2' Conflicts: org.simantics.pythonlink.win32.x86_64/jnipython.dll org.simantics.pythonlink.win32.x86_64/src/sclpy.c org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java Change-Id: I4a07bce4c1f4a0134ad774161ff79821f0d7e018 --- ac16ebed6a3e0932f774ca3ee5963ed776ef6c08 diff --cc org.simantics.pythonlink.win32.x86_64/.cproject index ccc5a9d,ccc5a9d..86dd825 --- a/org.simantics.pythonlink.win32.x86_64/.cproject +++ b/org.simantics.pythonlink.win32.x86_64/.cproject @@@ -4,7 -4,7 +4,7 @@@ -- ++ @@@ -68,7 -68,7 +68,7 @@@ -- ++ diff --cc org.simantics.pythonlink.win32.x86_64/jnipython.dll index 1770fb7,dbf7cb4..44ca25d Binary files differ diff --cc org.simantics.pythonlink.win32.x86_64/src/sclpy.c index a6c64ab,8e41834..4881cc7 --- a/org.simantics.pythonlink.win32.x86_64/src/sclpy.c +++ b/org.simantics.pythonlink.win32.x86_64/src/sclpy.c @@@ -1,1369 -1,1089 +1,1170 @@@ - /////////////////////////////////////////////////////// - // // - // 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 - - jint throwException( JNIEnv *env, char *className, char *message ) - { - jclass exClass = (*env)->FindClass( env, className); - if (exClass == NULL) { - return 0; - } - - return (*env)->ThrowNew( env, exClass, message ); - } - - jint throwPythonException( JNIEnv *env, char *message ) { - return throwException( env, PYTHON_EXCEPTION, message ); - } - - jint throwIllegalArgumentException( JNIEnv *env, 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 initCalled = 0; - int hasNumpy = 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 NULL; - - { - 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 (!initCalled) { - Py_Initialize(); - initCalled = 1; - - { - 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; - } - - sprintf(name, "SCL_%d", ++moduleCount); - - { - 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 = PyState_FindModule(modDef); - Py_XDECREF(module); - PyState_RemoveModule(modDef); - free((char*)modDef->m_name); - free(modDef); - } - - 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, "", "([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, "", "(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; - } - - JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jboolean value) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonBool(value); - - setPythonVariable(module, pythonName, val); - } - - JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jbooleanArray value) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonBooleanList(env, value); - - setPythonVariable(module, pythonName, val); - } - - JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlong value) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = PyLong_FromLongLong(value); - - setPythonVariable(module, pythonName, val); - } - - JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jintArray value) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonIntegerList(env, value); - - setPythonVariable(module, pythonName, val); - } - - JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlongArray value) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonLongList(env, value); - - setPythonVariable(module, pythonName, val); - } - - JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdouble value) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = PyFloat_FromDouble(value); - - setPythonVariable(module, pythonName, val); - } - - JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonFloatArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jfloatArray value) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonFloatList(env, value); - - setPythonVariable(module, pythonName, val); - } - - JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdoubleArray value) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonDoubleList(env, value); - - setPythonVariable(module, pythonName, val); - } - - JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonStringVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jstring value) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonString(env, value); - - setPythonVariable(module, pythonName, val); - } - - JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobjectArray value) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonStringList(env, value); - - setPythonVariable(module, pythonName, val); - } - - 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; - } - - { - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonNDArray(env, value); - - setPythonVariable(module, pythonName, val); - } - } - - 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); - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonObject(env, value, binding); - - setPythonVariable(module, pythonName, val); - } - - 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); - - PyErr_Clear(); - { - jclass sclReportingWriterClass = (*env)->FindClass(env, SCL_REPORTING_WRITER_CLASS); - jmethodID constructor = (*env)->GetMethodID(env, sclReportingWriterClass, "", "()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 { - throwPythonException(env, "Internal error, no message"); - } - 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"); - } - } - } - - (*env)->ReleaseStringUTFChars(env, statement, utfchars); - - if (sclWriter != NULL) { - (*env)->CallVoidMethod(env, sclWriter, flushMethod); - } - - currentEnv = NULL; - sclWriter = NULL; - - return result != NULL ? 0 : 1; - } - } - } - - JNIEXPORT jstring JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0; - } - - if (!PyUnicode_Check(value)) { - throwPythonException(env, "Python variable not a string"); - return 0; - } - - { - jstring result = pythonStringAsJavaString(env, value); - return result; - } - } - - JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0; - } - - if (!PySequence_Check(value)) { - throwPythonException(env, "Python variable not a sequence"); - return 0; - } - - { - jobjectArray result = pythonSequenceAsStringArray(env, value); - return result; - } - } - - JNIEXPORT jboolean JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0; - } - - if (!PyBool_Check(value)) { - throwPythonException(env, "Python variable not a boolean"); - return 0; - } - - return value == Py_True; - } - - JNIEXPORT jbooleanArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0; - } - - if (!PySequence_Check(value)) { - throwPythonException(env, "Python variable not a sequence"); - return 0; - } - - { - jbooleanArray result = pythonSequenceAsBooleanArray(env, value); - return result; - } - } - - JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0; - } - - if (!PyLong_Check(value)) { - throwPythonException(env, "Python variable not an integer"); - return 0; - } - - { - jlong result = PyLong_AsLongLong(value); - return result; - } - } - - JNIEXPORT jintArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return NULL; - } - - if (!PySequence_Check(value)) { - throwPythonException(env, "Python variable not a sequence"); - return NULL; - } - - { - jintArray result = pythonSequenceAsIntegerArray(env, value); - return result; - } - } - - JNIEXPORT jlongArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return NULL; - } - - if (!PySequence_Check(value)) { - throwPythonException(env, "Python variable not a sequence"); - return NULL; - } - - { - jlongArray result = pythonSequenceAsLongArray(env, value); - return result; - } - } - - JNIEXPORT jdouble JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0.0; - } - - if (!PyFloat_Check(value)) { - throwPythonException(env, "Python variable not a float"); - return 0.0; - } - - { - jdouble result = PyFloat_AsDouble(value); - return result; - } - } - - JNIEXPORT jdoubleArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return NULL; - } - - if (!PySequence_Check(value)) { - throwPythonException(env, "Python variable not a sequence"); - return NULL; - } - - { - jdoubleArray result = pythonSequenceAsDoubleArray(env, value); - return result; - } - } - - JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - - if (!hasNumpy) { - throwPythonException(env, "Importing numpy failed"); - return NULL; - } - - { - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return NULL; - } - - if (!PyArray_Check(value)) { - throwPythonException(env, "Python variable not an ndarray"); - return NULL; - } - - if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) { - throwPythonException(env, "Only ndarrays of type double are supported"); - return NULL; - } - - { - jobject result = pythonArrayAsNDArray(env, (PyArrayObject *)value); - return result; - } - } - } - - JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return NULL; - } - - hasNumpy = _import_array() != -1; - - { - jobject result = pythonObjectAsObject(env, value); - return result; - } - } - - JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); - PyObject *dict = PyModule_GetDict(module); - - PyObject *pythonName = getPythonString(env, variableName); - - if (!PyDict_Contains(dict, pythonName)) { - return 0; - } - - { - PyObject *value = PyDict_GetItem(dict, pythonName); - - jint result; - - 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; - - return result; - } - } - - JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(JNIEnv *env, jobject thisObj, jlong contextID) { - PyObject *module = getModule(contextID); - PyObject *dict = PyModule_GetDict(module); - - PyObject *keys = PyDict_Keys(dict); - Py_ssize_t size = PyList_Size(keys); - - jobjectArray result = (*env)->NewObjectArray(env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL); - - Py_ssize_t i; - for (i = 0; i < size; i++) { - jstring javaName = pythonStringAsJavaString(env, PyList_GetItem(keys, i)); - (*env)->SetObjectArrayElement(env, result, (jint)i, javaName); - } - - Py_XDECREF(keys); - - 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 - } + /////////////////////////////////////////////////////// + // // + // 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 + -jint throwException( JNIEnv *env, char *className, char *message ) ++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, char *message ) { ++jint throwPythonException( JNIEnv *env, const char *message ) { + return throwException( env, PYTHON_EXCEPTION, message ); + } + -jint throwIllegalArgumentException( JNIEnv *env, char *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 = PyModule_New(name); - PyObject *main = PyImport_AddModule("__main__"); ++ 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); + - PyDict_Merge(PyModule_GetDict(module), PyModule_GetDict(main), 0); - PyEval_SaveThread(); - return (jlong)module; ++ { ++ 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) { - PyObject *module = (PyObject*)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, "", "([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, "", "(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 = (PyObject*)contextID; \ ++ 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 = (PyObject*)contextID; ++ 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 = (PyObject*)contextID; ++ 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 = (PyObject*)contextID; ++ 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, "", "()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 = (PyObject*)contextID; ++ 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 = (PyObject*)contextID; ++ 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 + } diff --cc org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java index 2063c0b,ecf925d..16b0234 --- a/org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java +++ b/org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java @@@ -1,303 -1,294 +1,303 @@@ - package org.simantics.pythonlink; - - import java.io.Closeable; - import java.util.HashSet; - import java.util.Set; - import java.util.concurrent.Callable; - import java.util.concurrent.ExecutionException; - import java.util.concurrent.ExecutorService; - import java.util.concurrent.Executors; - import java.util.regex.Pattern; - - import org.simantics.databoard.Bindings; - import org.simantics.databoard.binding.Binding; - import org.simantics.databoard.binding.error.BindingException; - import org.simantics.databoard.binding.mutable.Variant; - import org.simantics.scl.runtime.SCLContext; - import org.simantics.scl.runtime.reporting.SCLReportingHandler; - - public class PythonContext implements Closeable { - private long contextID; - - public interface Listener { - void updated(String variableName); - void closed(); - } - - static ExecutorService pythonExecutor = Executors.newSingleThreadExecutor(); - - Set listeners = new HashSet<>(); - - public enum VariableType { - NO_VARIABLE, - BOOLEAN, - LONG, - FLOAT, - STRING, - BYTEARRAY, - DICTIONARY, - NDARRAY, - SEQUENCE, - UNKNOWN - } - - static Pattern namePattern = Pattern.compile("([a-zA-Z_][a-zA-Z_0-9]*)"); - - PythonContext() { - contextID = createContextImpl(); - } - - public void addListener(Listener listener) { - listeners.add(listener); - } - - public void removeListener(Listener listener) { - listeners.remove(listener); - } - - @Override - public void close() { - long id = contextID; - contextID = 0; - if (id != 0) deleteContextImpl(id); - - for (Listener l : listeners) { - l.closed(); - } - } - - public boolean isOpen() { - return contextID != 0; - } - - @Override - protected void finalize() throws Throwable { - super.finalize(); - close(); - } - - public void executePythonStatement(String statement) { - SCLContext sclContext = SCLContext.getCurrent(); - - execute(() -> { - SCLContext.push(sclContext); - executePythonStatementImpl( contextID, statement ); - SCLContext.pop(); - }); - - for (Listener l : listeners) { l.updated(null); } - } - - // Setters - - public void setPythonBooleanVariable(String variableName, boolean value) { - checkValidName(variableName); - execute(() -> setPythonBooleanVariableImpl(contextID, variableName, value)); - for (Listener l : listeners) { l.updated(variableName); } - } - - public void setPythonIntegerVariable(String variableName, int value) { - checkValidName(variableName); - execute(() -> setPythonLongVariableImpl(contextID, variableName, value)); - for (Listener l : listeners) { l.updated(variableName); } - } - public void setPythonLongVariable(String variableName, long value) { - checkValidName(variableName); - execute(() -> setPythonLongVariableImpl(contextID, variableName, value)); - for (Listener l : listeners) { l.updated(variableName); } - } - public void setPythonDoubleVariable(String variableName, double value) { - checkValidName(variableName); - execute(() -> setPythonDoubleVariableImpl(contextID, variableName, value)); - for (Listener l : listeners) { l.updated(variableName); } - } - public void setPythonStringVariable(String variableName, String value) { - checkValidName(variableName); - execute(() -> setPythonStringVariableImpl(contextID, variableName, value)); - for (Listener l : listeners) { l.updated(variableName); } - } - - public void setPythonBooleanArrayVariable(String variableName, boolean[] value) { - checkValidName(variableName); - execute(() -> setPythonBooleanArrayVariableImpl(contextID, variableName, value)); - for (Listener l : listeners) { l.updated(variableName); } - } - public void setPythonIntegerArrayVariable(String variableName, int[] value) { - checkValidName(variableName); - execute(() -> setPythonIntegerArrayVariableImpl(contextID, variableName, value)); - for (Listener l : listeners) { l.updated(variableName); } - } - public void setPythonLongArrayVariable(String variableName, long[] value) { - checkValidName(variableName); - execute(() -> setPythonLongArrayVariableImpl(contextID, variableName, value)); - for (Listener l : listeners) { l.updated(variableName); } - } - public void setPythonDoubleArrayVariable(String variableName, double[] value) { - checkValidName(variableName); - execute(() -> setPythonDoubleArrayVariableImpl(contextID, variableName, value)); - for (Listener l : listeners) { l.updated(variableName); } - } - public void setPythonStringArrayVariable(String variableName, String[] value) { - checkValidName(variableName); - execute(() -> setPythonStringArrayVariableImpl(contextID, variableName, value)); - for (Listener l : listeners) { l.updated(variableName); } - } - - // Getters - - public boolean getPythonBooleanVariable(String variableName) { - checkValidName(variableName); - return getPythonBooleanVariableImpl(contextID, variableName); - } - public int getPythonIntegerVariable(String variableName) { - checkValidName(variableName); - long value = execute(() -> getPythonLongVariableImpl(contextID, variableName)); - if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) - throw new RuntimeException("Python value not in integer range"); - return (int) value; - } - public long getPythonLongVariable(String variableName) { - checkValidName(variableName); - return execute(() -> getPythonLongVariableImpl(contextID, variableName)); - } - public double getPythonDoubleVariable(String variableName) { - checkValidName(variableName); - return execute(() -> getPythonDoubleVariableImpl(contextID, variableName)); - } - public String getPythonStringVariable(String variableName) { - checkValidName(variableName); - return execute(() -> getPythonStringVariableImpl(contextID, variableName)); - } - - public boolean[] getPythonBooleanArrayVariable(String variableName) { - checkValidName(variableName); - return execute(() -> getPythonBooleanArrayVariableImpl(contextID, variableName)); - } - public int[] getPythonIntegerArrayVariable(String variableName) { - checkValidName(variableName); - return execute(() -> getPythonIntegerArrayVariableImpl(contextID, variableName)); - } - public long[] getPythonLongArrayVariable(String variableName) { - checkValidName(variableName); - return execute(() -> getPythonLongArrayVariableImpl(contextID, variableName)); - } - public double[] getPythonDoubleArrayVariable(String variableName) { - checkValidName(variableName); - return execute(() -> getPythonDoubleArrayVariableImpl(contextID, variableName)); - } - public String[] getPythonStringArrayVariable(String variableName) { - checkValidName(variableName); - return execute(() -> getPythonStringArrayVariableImpl(contextID, variableName)); - } - - public void setPythonNDArrayVariable(String variableName, NDArray value) { - checkValidName(variableName); - execute(() -> setPythonNDArrayVariableImpl(contextID, variableName, value)); - } - public NDArray getPythonNDArrayVariable(String variableName) { - checkValidName(variableName); - return execute(() -> getPythonNDArrayVariableImpl(contextID, variableName)); - } - - public Object getPythonVariantVariable(String variableName, Binding binding) { - checkValidName(variableName); - Object result = execute(() -> getPythonVariantVariableImpl(contextID, variableName)); - try { - return Bindings.OBJECT.getContent(result, binding); - } catch (BindingException e) { - throw new RuntimeException(e); - } - } - - public Variant getPythonVariantVariable(String variableName) { - checkValidName(variableName); - return Variant.ofInstance(execute(() -> getPythonVariantVariableImpl(contextID, variableName))); - } - - public void setPythonVariantVariable(String variableName, Variant value) { - setPythonVariantVariable(variableName, value.getValue(), value.getBinding()); - } - - public void setPythonVariantVariable(String variableName, Object value, Binding binding) { - checkValidName(variableName); - if (!binding.isInstance(value)) throw new IllegalArgumentException("Invalid object binding"); - - execute(() -> setPythonVariantVariableImpl(contextID, variableName, value, binding)); - - for (Listener l : listeners) { l.updated(variableName); } - } - - public VariableType getPythonVariableType(String variableName) { - checkValidName(variableName); - int code = execute(() -> getPythonVariableTypeImpl(contextID, variableName)); - - VariableType[] values = VariableType.values(); - if (code < 0 || code >= values.length) - return VariableType.UNKNOWN; - - return values[code]; - } - - public String[] getPythonVariableNames() { - return execute(() -> getPythonVariableNamesImpl(contextID)); - } - - private static void checkValidName(String variableName) { - if (!namePattern.matcher(variableName).matches()) - throw new IllegalArgumentException("Invalid Python variable name " + variableName); - } - - static void execute(Runnable job) { - try { - pythonExecutor.submit(job).get(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - } - - static V execute(Callable job) { - try { - return pythonExecutor.submit(job).get(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - } - - // Native function declarations - private static native long createContextImpl(); - private static native void deleteContextImpl(long contextID); - - private static native int executePythonStatementImpl(long contextID, String statement); - - private static native void setPythonBooleanVariableImpl(long contextID, String variableName, boolean value); - private static native void setPythonLongVariableImpl(long contextID, String variableName, long value); - private static native void setPythonDoubleVariableImpl(long contextID, String variableName, double value); - private static native void setPythonStringVariableImpl(long contextID, String variableName, String value); - - private static native void setPythonBooleanArrayVariableImpl(long contextID, String variableName, boolean[] value); - private static native void setPythonIntegerArrayVariableImpl(long contextID, String variableName, int[] value); - private static native void setPythonLongArrayVariableImpl(long contextID, String variableName, long[] value); - private static native void setPythonDoubleArrayVariableImpl(long contextID, String variableName, double[] value); - private static native void setPythonStringArrayVariableImpl(long contextID, String variableName, String[] value); - - private static native boolean getPythonBooleanVariableImpl(long contextID, String variableName); - private static native long getPythonLongVariableImpl(long contextID, String variableName); - private static native double getPythonDoubleVariableImpl(long contextID, String variableName); - private static native String getPythonStringVariableImpl(long contextID, String variableName); - - private static native boolean[] getPythonBooleanArrayVariableImpl(long contextID, String variableName); - private static native long[] getPythonLongArrayVariableImpl(long contextID, String variableName); - private static native int[] getPythonIntegerArrayVariableImpl(long contextID, String variableName); - private static native double[] getPythonDoubleArrayVariableImpl(long contextID, String variableName); - private static native String[] getPythonStringArrayVariableImpl(long contextID, String variableName); - - private static native void setPythonNDArrayVariableImpl(long contextID, String variableName, NDArray value); - private static native NDArray getPythonNDArrayVariableImpl(long contextID, String variableName); - - private static native void setPythonVariantVariableImpl(long contextID, String variableName, Object value, Binding binding); - private static native Object getPythonVariantVariableImpl(long contextID, String variableName); - - private static native int getPythonVariableTypeImpl(long contextID, String variableName); - - private static native String[] getPythonVariableNamesImpl(long contextID); - } + package org.simantics.pythonlink; + + import java.io.Closeable; + import java.util.HashSet; + import java.util.Set; + import java.util.concurrent.Callable; + import java.util.concurrent.ExecutionException; + import java.util.concurrent.ExecutorService; + import java.util.concurrent.Executors; + import java.util.regex.Pattern; + + import org.simantics.databoard.Bindings; + import org.simantics.databoard.binding.Binding; + import org.simantics.databoard.binding.error.BindingException; + import org.simantics.databoard.binding.mutable.Variant; ++import org.simantics.scl.runtime.SCLContext; ++import org.simantics.scl.runtime.reporting.SCLReportingHandler; + + public class PythonContext implements Closeable { + private long contextID; + + public interface Listener { + void updated(String variableName); + void closed(); + } + + static ExecutorService pythonExecutor = Executors.newSingleThreadExecutor(); + + Set listeners = new HashSet<>(); + + public enum VariableType { + NO_VARIABLE, + BOOLEAN, + LONG, + FLOAT, + STRING, + BYTEARRAY, + DICTIONARY, + NDARRAY, + SEQUENCE, + UNKNOWN + } + + static Pattern namePattern = Pattern.compile("([a-zA-Z_][a-zA-Z_0-9]*)"); + + PythonContext() { + contextID = execute(() -> createContextImpl()); + } + + public void addListener(Listener listener) { + listeners.add(listener); + } + + public void removeListener(Listener listener) { + listeners.remove(listener); + } + + @Override + public void close() { + long id = contextID; + contextID = 0; + if (id != 0) execute(() -> deleteContextImpl(id)); + + for (Listener l : listeners) { + l.closed(); + } + } + + public boolean isOpen() { + return contextID != 0; + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + close(); + } + + public void executePythonStatement(String statement) { - execute(() -> executePythonStatementImpl( contextID, statement )); ++ SCLContext sclContext = SCLContext.getCurrent(); ++ ++ execute(() -> { ++ SCLContext.push(sclContext); ++ executePythonStatementImpl( contextID, statement ); ++ SCLContext.pop(); ++ }); ++ + for (Listener l : listeners) { l.updated(null); } + } + + // Setters + + public void setPythonBooleanVariable(String variableName, boolean value) { + checkValidName(variableName); + execute(() -> setPythonBooleanVariableImpl(contextID, variableName, value)); + for (Listener l : listeners) { l.updated(variableName); } + } + + public void setPythonIntegerVariable(String variableName, int value) { + checkValidName(variableName); + execute(() -> setPythonLongVariableImpl(contextID, variableName, value)); + for (Listener l : listeners) { l.updated(variableName); } + } + public void setPythonLongVariable(String variableName, long value) { + checkValidName(variableName); + execute(() -> setPythonLongVariableImpl(contextID, variableName, value)); + for (Listener l : listeners) { l.updated(variableName); } + } + public void setPythonDoubleVariable(String variableName, double value) { + checkValidName(variableName); + execute(() -> setPythonDoubleVariableImpl(contextID, variableName, value)); + for (Listener l : listeners) { l.updated(variableName); } + } + public void setPythonStringVariable(String variableName, String value) { + checkValidName(variableName); + execute(() -> setPythonStringVariableImpl(contextID, variableName, value)); + for (Listener l : listeners) { l.updated(variableName); } + } + + public void setPythonBooleanArrayVariable(String variableName, boolean[] value) { + checkValidName(variableName); + execute(() -> setPythonBooleanArrayVariableImpl(contextID, variableName, value)); + for (Listener l : listeners) { l.updated(variableName); } + } + public void setPythonIntegerArrayVariable(String variableName, int[] value) { + checkValidName(variableName); + execute(() -> setPythonIntegerArrayVariableImpl(contextID, variableName, value)); + for (Listener l : listeners) { l.updated(variableName); } + } + public void setPythonLongArrayVariable(String variableName, long[] value) { + checkValidName(variableName); + execute(() -> setPythonLongArrayVariableImpl(contextID, variableName, value)); + for (Listener l : listeners) { l.updated(variableName); } + } + public void setPythonDoubleArrayVariable(String variableName, double[] value) { + checkValidName(variableName); + execute(() -> setPythonDoubleArrayVariableImpl(contextID, variableName, value)); + for (Listener l : listeners) { l.updated(variableName); } + } + public void setPythonStringArrayVariable(String variableName, String[] value) { + checkValidName(variableName); + execute(() -> setPythonStringArrayVariableImpl(contextID, variableName, value)); + for (Listener l : listeners) { l.updated(variableName); } + } + + // Getters + + public boolean getPythonBooleanVariable(String variableName) { + checkValidName(variableName); + return getPythonBooleanVariableImpl(contextID, variableName); + } + public int getPythonIntegerVariable(String variableName) { + checkValidName(variableName); + long value = execute(() -> getPythonLongVariableImpl(contextID, variableName)); + if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) + throw new RuntimeException("Python value not in integer range"); + return (int) value; + } + public long getPythonLongVariable(String variableName) { + checkValidName(variableName); + return execute(() -> getPythonLongVariableImpl(contextID, variableName)); + } + public double getPythonDoubleVariable(String variableName) { + checkValidName(variableName); + return execute(() -> getPythonDoubleVariableImpl(contextID, variableName)); + } + public String getPythonStringVariable(String variableName) { + checkValidName(variableName); + return execute(() -> getPythonStringVariableImpl(contextID, variableName)); + } + + public boolean[] getPythonBooleanArrayVariable(String variableName) { + checkValidName(variableName); + return execute(() -> getPythonBooleanArrayVariableImpl(contextID, variableName)); + } + public int[] getPythonIntegerArrayVariable(String variableName) { + checkValidName(variableName); + return execute(() -> getPythonIntegerArrayVariableImpl(contextID, variableName)); + } + public long[] getPythonLongArrayVariable(String variableName) { + checkValidName(variableName); + return execute(() -> getPythonLongArrayVariableImpl(contextID, variableName)); + } + public double[] getPythonDoubleArrayVariable(String variableName) { + checkValidName(variableName); + return execute(() -> getPythonDoubleArrayVariableImpl(contextID, variableName)); + } + public String[] getPythonStringArrayVariable(String variableName) { + checkValidName(variableName); + return execute(() -> getPythonStringArrayVariableImpl(contextID, variableName)); + } + + public void setPythonNDArrayVariable(String variableName, NDArray value) { + checkValidName(variableName); + execute(() -> setPythonNDArrayVariableImpl(contextID, variableName, value)); + } + public NDArray getPythonNDArrayVariable(String variableName) { + checkValidName(variableName); + return execute(() -> getPythonNDArrayVariableImpl(contextID, variableName)); + } + + public Object getPythonVariantVariable(String variableName, Binding binding) { + checkValidName(variableName); + Object result = execute(() -> getPythonVariantVariableImpl(contextID, variableName)); + try { + return Bindings.OBJECT.getContent(result, binding); + } catch (BindingException e) { + throw new RuntimeException(e); + } + } + + public Variant getPythonVariantVariable(String variableName) { + checkValidName(variableName); + return Variant.ofInstance(execute(() -> getPythonVariantVariableImpl(contextID, variableName))); + } + + public void setPythonVariantVariable(String variableName, Variant value) { + setPythonVariantVariable(variableName, value.getValue(), value.getBinding()); + } + + public void setPythonVariantVariable(String variableName, Object value, Binding binding) { + checkValidName(variableName); + if (!binding.isInstance(value)) throw new IllegalArgumentException("Invalid object binding"); + + execute(() -> setPythonVariantVariableImpl(contextID, variableName, value, binding)); + + for (Listener l : listeners) { l.updated(variableName); } + } + + public VariableType getPythonVariableType(String variableName) { + checkValidName(variableName); + int code = execute(() -> getPythonVariableTypeImpl(contextID, variableName)); + + VariableType[] values = VariableType.values(); + if (code < 0 || code >= values.length) + return VariableType.UNKNOWN; + + return values[code]; + } + + public String[] getPythonVariableNames() { + return execute(() -> getPythonVariableNamesImpl(contextID)); + } + + private static void checkValidName(String variableName) { + if (!namePattern.matcher(variableName).matches()) + throw new IllegalArgumentException("Invalid Python variable name " + variableName); + } + + static void execute(Runnable job) { + try { + pythonExecutor.submit(job).get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + + static V execute(Callable job) { + try { + return pythonExecutor.submit(job).get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + + // Native function declarations + private static native long createContextImpl(); + private static native void deleteContextImpl(long contextID); + + private static native int executePythonStatementImpl(long contextID, String statement); + + private static native void setPythonBooleanVariableImpl(long contextID, String variableName, boolean value); + private static native void setPythonLongVariableImpl(long contextID, String variableName, long value); + private static native void setPythonDoubleVariableImpl(long contextID, String variableName, double value); + private static native void setPythonStringVariableImpl(long contextID, String variableName, String value); + + private static native void setPythonBooleanArrayVariableImpl(long contextID, String variableName, boolean[] value); + private static native void setPythonIntegerArrayVariableImpl(long contextID, String variableName, int[] value); + private static native void setPythonLongArrayVariableImpl(long contextID, String variableName, long[] value); + private static native void setPythonDoubleArrayVariableImpl(long contextID, String variableName, double[] value); + private static native void setPythonStringArrayVariableImpl(long contextID, String variableName, String[] value); + + private static native boolean getPythonBooleanVariableImpl(long contextID, String variableName); + private static native long getPythonLongVariableImpl(long contextID, String variableName); + private static native double getPythonDoubleVariableImpl(long contextID, String variableName); + private static native String getPythonStringVariableImpl(long contextID, String variableName); + + private static native boolean[] getPythonBooleanArrayVariableImpl(long contextID, String variableName); + private static native long[] getPythonLongArrayVariableImpl(long contextID, String variableName); + private static native int[] getPythonIntegerArrayVariableImpl(long contextID, String variableName); + private static native double[] getPythonDoubleArrayVariableImpl(long contextID, String variableName); + private static native String[] getPythonStringArrayVariableImpl(long contextID, String variableName); + + private static native void setPythonNDArrayVariableImpl(long contextID, String variableName, NDArray value); + private static native NDArray getPythonNDArrayVariableImpl(long contextID, String variableName); + + private static native void setPythonVariantVariableImpl(long contextID, String variableName, Object value, Binding binding); + private static native Object getPythonVariantVariableImpl(long contextID, String variableName); + + private static native int getPythonVariableTypeImpl(long contextID, String variableName); + + private static native String[] getPythonVariableNamesImpl(long contextID); + }