/////////////////////////////////////////////////////// // // // 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 throwIllegalArgumentException( JNIEnv *env, char *message ) { return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message ); } int moduleCount = 0; int initCalled = 0; int hasNumpy = 0; JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) { char name[16]; if (!initCalled) { Py_Initialize(); initCalled = 1; hasNumpy = _import_array(); hasNumpy = hasNumpy != -1; } sprintf(name, "SCL_%d", ++moduleCount); { PyObject *module = PyModule_New(name); PyObject *main = PyImport_AddModule("__main__"); PyDict_Merge(PyModule_GetDict(module), PyModule_GetDict(main), 0); return (jlong)module; } } JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) { PyObject *module = (PyObject*)contextID; Py_XDECREF(module); } 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 ((*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 { throwException(env, RUNTIME_EXCEPTION, "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 { throwException(env, RUNTIME_EXCEPTION, "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 { throwException(env, RUNTIME_EXCEPTION, "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 { throwException(env, RUNTIME_EXCEPTION, "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 { throwException(env, RUNTIME_EXCEPTION, "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) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)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 = (PyObject*)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 = (PyObject*)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 = (PyObject*)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 = (PyObject*)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 = (PyObject*)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 = (PyObject*)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 = (PyObject*)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 = (PyObject*)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 = (PyObject*)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 = (PyObject*)contextID; if (!hasNumpy) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)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 = (PyObject*)contextID; const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL); PyErr_Clear(); { PyObject *globals; globals = PyModule_GetDict(module); { PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals); PyObject *exceptionType = PyErr_Occurred(); if (exceptionType != NULL) { PyObject *exception, *stackTrace; char *message; PyErr_Fetch(&exceptionType, &exception, &stackTrace); message = PyUnicode_AsUTF8(exception); throwException(env, RUNTIME_EXCEPTION, message); } (*env)->ReleaseStringUTFChars(env, statement, utfchars); return result != NULL ? 0 : 1; } } } JNIEXPORT jstring JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { PyObject *module = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); return 0; } if (!PyUnicode_Check(value)) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); return 0; } if (!PySequence_Check(value)) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); return 0; } if (!PyBool_Check(value)) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); return 0; } if (!PySequence_Check(value)) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); return 0; } if (!PyLong_Check(value)) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); return NULL; } if (!PySequence_Check(value)) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); return NULL; } if (!PySequence_Check(value)) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); return 0.0; } if (!PyFloat_Check(value)) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); return NULL; } if (!PySequence_Check(value)) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)contextID; if (!hasNumpy) { throwException(env, RUNTIME_EXCEPTION, "Importing numpy failed"); return NULL; } { PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); return NULL; } if (!PyArray_Check(value)) { throwException(env, RUNTIME_EXCEPTION, "Python variable not an ndarray"); return NULL; } if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { throwException(env, RUNTIME_EXCEPTION, "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 = (PyObject*)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 = (PyObject*)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 }