1 ///////////////////////////////////////////////////////
3 // VTT Technical Research Centre of Finland LTD //
4 // For internal use only. Do not redistribute. //
7 // Antton Tapani ext-antton.tapani@vtt.fi //
9 // Last modified by Antton Tapani 9.2016 //
11 ///////////////////////////////////////////////////////
17 jint throwException( JNIEnv *env, char *className, const char *message )
19 jclass exClass = (*env)->FindClass( env, className);
20 if (exClass == NULL) {
24 return (*env)->ThrowNew( env, exClass, message );
27 jint throwPythonException( JNIEnv *env, const char *message ) {
28 return throwException( env, PYTHON_EXCEPTION, message );
31 jint throwIllegalArgumentException( JNIEnv *env, const char *message ) {
32 return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message );
35 PyObject* getModule(jlong contextID) {
36 return PyState_FindModule((PyModuleDef*) contextID);
37 // return PyImport_AddModule("__main__");
42 PyThreadState *main_ts = 0;
44 static JNIEnv *currentEnv = NULL;
45 jobject sclWriter = NULL;
48 writeToSCL(PyObject *self, PyObject *args)
50 if (currentEnv != NULL && sclWriter != NULL) {
53 JNIEnv *env = currentEnv;
55 if (!PyArg_ParseTuple(args, "u#", &what, &length))
59 PyThreadState *my_ts = PyThreadState_Get();
60 if (my_ts == main_ts) {
61 jclass writerClass = (*env)->FindClass(env, WRITER_CLASS);
62 jmethodID writeMethod = (*env)->GetMethodID(env, writerClass, "write", "([CII)V");
63 jcharArray chars = (*env)->NewCharArray(env, (jsize)length);
65 (*env)->SetCharArrayRegion(env, chars, 0, length, what);
66 Py_BEGIN_ALLOW_THREADS
67 (*env)->CallVoidMethod(env, sclWriter, writeMethod, chars, 0, length);
79 flushSCL(PyObject *self, PyObject *args)
81 if (currentEnv != NULL && sclWriter != NULL) {
82 JNIEnv *env = currentEnv;
83 PyThreadState *my_ts = PyThreadState_Get();
84 if (my_ts != main_ts) {
85 // TODO: Process calls from other threads
90 jclass writerClass = (*env)->FindClass(env, WRITER_CLASS);
91 jmethodID flushMethod = (*env)->GetMethodID(env, writerClass, "flush", "()V");
93 Py_BEGIN_ALLOW_THREADS
94 (*env)->CallVoidMethod(env, sclWriter, flushMethod);
102 static PyMethodDef sclWriterMethods[] = {
103 {"write", writeToSCL, METH_VARARGS, "Write something."},
104 {"flush", flushSCL, METH_VARARGS, "Flush output."},
105 {NULL, NULL, 0, NULL}
108 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_initializePython(JNIEnv *env, jobject thisObj, jobject writer) {
112 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods, };
113 PyObject *m = PyModule_Create(&moduledef);
115 sclWriter = (*env)->NewGlobalRef(env, writer);
117 if (m == NULL) throwException(env, PYTHON_EXCEPTION, "Failed to create SCL writer module");
119 PySys_SetObject("stdout", m);
120 PySys_SetObject("stderr", m);
123 hasNumpy = _import_array();
124 hasNumpy = hasNumpy != -1;
126 main_ts = PyEval_SaveThread();
129 JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) {
136 sprintf(name, "SCL_%d", ++moduleCount);
138 PyEval_RestoreThread(main_ts);
141 PyModuleDef *modDef = malloc(sizeof(PyModuleDef));
142 memset(modDef, 0, sizeof(PyModuleDef));
143 modDef->m_name = strdup(name);
144 modDef->m_doc = NULL;
147 module = PyModule_Create(modDef);
149 PyState_AddModule(module, modDef);
152 PyObject *builtin = PyImport_AddModule("builtins");
153 PyObject *dict = PyModule_GetDict(module);
154 PyDict_SetItemString(dict, "__builtin__", builtin);
155 PyDict_SetItemString(dict, "__builtins__", builtin);
158 return (jlong)modDef;
163 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) {
164 PyModuleDef *modDef = (PyModuleDef*)contextID;
166 PyEval_RestoreThread(main_ts);
167 module = PyState_FindModule(modDef);
169 PyState_RemoveModule(modDef);
170 free((char*)modDef->m_name);
175 PyObject *getPythonBool(jboolean value) {
184 PyObject *getPythonString(JNIEnv *env, jstring string) {
185 jsize len = (*env)->GetStringLength(env, string);
186 const jchar *chars = (*env)->GetStringChars(env, string, NULL);
188 PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
190 (*env)->ReleaseStringChars(env, string, chars);
194 PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) {
195 jsize nitems = (*env)->GetArrayLength(env, value);
196 jint *values = (*env)->GetIntArrayElements(env, value, NULL);
197 jclass stringClass = (*env)->FindClass(env, STRING_CLASS);
200 PyObject *result = PyList_New(nitems);
201 for (i = 0; i < nitems; i++) {
202 jobject item = (*env)->GetObjectArrayElement(env, value, i);
203 if (item != NULL && (*env)->IsInstanceOf(env, item, stringClass)) {
204 PyList_SetItem(result, i, getPythonString(env, (jstring)item));
207 PyList_SetItem(result, i, Py_None);
211 (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
215 PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) {
216 jsize nitems = (*env)->GetArrayLength(env, value);
217 jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL);
220 PyObject *result = PyList_New(nitems);
221 for (i = 0; i < nitems; i++) {
222 PyList_SetItem(result, i, getPythonBool(values[i]));
225 (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT);
229 PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) {
230 jint len = (*env)->GetArrayLength(env, value);
231 jbyte *values = (*env)->GetByteArrayElements(env, value, NULL);
233 PyObject *result = PyByteArray_FromStringAndSize(values, len);
235 (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT);
239 PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) {
240 jsize nitems = (*env)->GetArrayLength(env, value);
241 jint *values = (*env)->GetIntArrayElements(env, value, NULL);
244 PyObject *result = PyList_New(nitems);
245 for (i = 0; i < nitems; i++) {
246 PyList_SetItem(result, i, PyLong_FromLong(values[i]));
249 (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
253 PyObject *getPythonLongList(JNIEnv *env, jlongArray value) {
254 jsize nitems = (*env)->GetArrayLength(env, value);
255 jlong *values = (*env)->GetLongArrayElements(env, value, NULL);
258 PyObject *result = PyList_New(nitems);
259 for (i = 0; i < nitems; i++) {
260 PyList_SetItem(result, i, PyLong_FromLongLong(values[i]));
263 (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT);
267 PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) {
268 jsize nitems = (*env)->GetArrayLength(env, value);
269 float *values = (*env)->GetFloatArrayElements(env, value, NULL);
272 PyObject *result = PyList_New(nitems);
273 for (i = 0; i < nitems; i++) {
274 PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i]));
277 (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT);
281 PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) {
282 jsize nitems = (*env)->GetArrayLength(env, value);
283 double *values = (*env)->GetDoubleArrayElements(env, value, NULL);
286 PyObject *result = PyList_New(nitems);
287 for (i = 0; i < nitems; i++) {
288 PyList_SetItem(result, i, PyFloat_FromDouble(values[i]));
291 (*env)->ReleaseDoubleArrayElements(env, value, values, JNI_ABORT);
295 PyObject *getPythonNDArray(JNIEnv *env, jobject value) {
296 jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
297 jmethodID dimsMethod = (*env)->GetMethodID(env, ndarrayClass, "dims", "()[I");
298 jmethodID getValuesMethod = (*env)->GetMethodID(env, ndarrayClass, "getValues", "()[D");
300 jintArray jdims = (*env)->CallObjectMethod(env, value, dimsMethod);
301 jsize ndims = (*env)->GetArrayLength(env, jdims);
302 jint *dims = (*env)->GetIntArrayElements(env, jdims, NULL);
304 jdoubleArray jvalues = (*env)->CallObjectMethod(env, value, getValuesMethod);
305 jsize len = (*env)->GetArrayLength(env, jvalues);
306 jdouble *values = (*env)->GetDoubleArrayElements(env, jvalues, NULL);
308 npy_intp *pyDims = (npy_intp*)malloc(ndims * sizeof(npy_intp));
310 jint i, nelem = ndims > 0 ? 1 : 0;
311 for (i = 0; i < ndims; i++) {
316 len = min(len, nelem);
319 PyObject *array = PyArray_EMPTY(ndims, pyDims, NPY_DOUBLE, 0);
320 double *data = (double *)PyArray_DATA((PyArrayObject*)array);
322 memcpy(data, values, len * sizeof(double));
326 (*env)->ReleaseDoubleArrayElements(env, jvalues, values, JNI_ABORT);
327 (*env)->ReleaseIntArrayElements(env, jdims, dims, JNI_ABORT);
333 PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) {
334 jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
335 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z");
337 jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object);
338 return getPythonBool(bvalue);
341 PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) {
342 jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS);
343 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B");
345 jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object);
346 return PyLong_FromLong(v);
349 PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) {
350 jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS);
351 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I");
353 jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object);
354 return PyLong_FromLong(v);
357 PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) {
358 jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS);
359 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J");
361 jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object);
362 return PyLong_FromLongLong(v);
365 PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) {
366 jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS);
367 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F");
369 jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object);
370 return PyFloat_FromDouble(v);
373 PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) {
374 jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
375 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D");
377 jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object);
378 return PyFloat_FromDouble(v);
381 PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) {
382 jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS);
383 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";");
385 jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
386 jsize len = (*env)->GetStringLength(env, string);
387 const jchar *chars = (*env)->GetStringChars(env, string, NULL);
389 PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
391 (*env)->ReleaseStringChars(env, string, chars);
395 PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) {
396 jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS);
397 jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
398 jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
399 jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
401 jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS);
402 jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";");
403 jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I");
405 jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
406 jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
408 jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
409 jint n = (*env)->CallIntMethod(env, type, getComponentCount);
412 PyObject *result = PyDict_New();
413 for (i = 0; i < n; i++) {
414 jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i);
415 jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField);
416 jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i);
417 jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i);
419 PyObject *item = getPythonObject(env, componentObject, componentBinding);
420 PyDict_SetItem(result, getPythonString(env, fieldName), item);
426 PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) {
427 jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS);
428 jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
429 jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
430 jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
432 jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
434 jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
436 PyObject *result = PyList_New(size);
439 for (i = 0; i < size; i++) {
440 jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i);
442 PyList_SetItem(result, i, getPythonObject(env, item, componentBinding));
444 PyList_SetItem(result, i, Py_None);
450 PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) {
451 jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS);
452 jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS);
453 jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";");
454 jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";");
455 jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
456 jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V");
458 jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod);
459 jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod);
461 jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
462 jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL);
463 jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL);
465 PyObject *result = PyDict_New();
468 (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values);
470 for (i = 0; i < size; i++) {
471 jobject key = (*env)->GetObjectArrayElement(env, keys, i);
472 jobject item = (*env)->GetObjectArrayElement(env, values, i);
473 PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding));
476 (*env)->DeleteLocalRef(env, keys);
477 (*env)->DeleteLocalRef(env, values);
482 PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) {
483 jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
484 jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z");
486 jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object);
489 jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
490 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
492 jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
493 jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
495 return getPythonObject(env, value, componentBinding);
502 PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) {
503 jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS);
504 jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
505 jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I");
506 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
507 jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
509 jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS);
510 jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";");
512 jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
513 jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
515 jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object);
516 jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
518 jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
519 jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag);
520 jstring compName = (*env)->GetObjectField(env, typeComponent, nameField);
522 jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag);
524 PyObject *result = PyTuple_New(2);
525 PyTuple_SetItem(result, 0, getPythonString(env, compName));
526 PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding));
531 PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) {
532 jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS);
533 jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
534 jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";");
536 jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object);
537 jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object);
539 return getPythonObject(env, content, contentBinding);
542 PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) {
543 jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
544 jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS);
545 jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS);
546 jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS);
547 jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS);
548 jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
549 jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS);
550 jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS);
551 jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS);
552 jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS);
553 jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
554 jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS);
555 jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS);
560 if ((*env)->IsInstanceOf(env, binding, booleanBinding)) {
561 return getPythonBooleanObject(env, value, binding);
563 else if ((*env)->IsInstanceOf(env, binding, byteBinding)) {
564 return getPythonByteObject(env, value, binding);
566 else if ((*env)->IsInstanceOf(env, binding, integerBinding)) {
567 return getPythonIntegerObject(env, value, binding);
569 else if ((*env)->IsInstanceOf(env, binding, longBinding)) {
570 return getPythonLongObject(env, value, binding);
572 else if ((*env)->IsInstanceOf(env, binding, floatBinding)) {
573 return getPythonFloatObject(env, value, binding);
575 else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) {
576 return getPythonDoubleObject(env, value, binding);
578 else if ((*env)->IsInstanceOf(env, binding, stringBinding)) {
579 return getPythonStringObject(env, value, binding);
581 else if ((*env)->IsInstanceOf(env, binding, recordBinding)) {
582 return getPythonRecordObject(env, value, binding);
584 else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) {
585 return getPythonArrayObject(env, value, binding);
587 else if ((*env)->IsInstanceOf(env, binding, mapBinding)) {
588 return getPythonMapObject(env, value, binding);
590 else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) {
591 return getPythonOptionalObject(env, value, binding);
593 else if ((*env)->IsInstanceOf(env, binding, untionBinding)) {
594 return getPythonUnionObject(env, value, binding);
596 else if ((*env)->IsInstanceOf(env, binding, variantBinding)) {
597 return getPythonVariantObject(env, value, binding);
604 void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) {
606 PyDict_SetItem(PyModule_GetDict(module), name, value);
613 static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {
619 npy_intp n = nContiguous(d+1, nd, strides, dims, ncont);
620 ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0;
625 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) {
627 (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data);
632 for (i = 0; i < dims[d]; i++) {
633 copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont);
638 jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) {
639 jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean");
640 jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;");
642 return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True));
645 jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) {
646 jclass longClass = (*env)->FindClass(env, "java/lang/Long");
647 jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;");
649 return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value));
652 jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) {
653 jclass doubleClass = (*env)->FindClass(env, "java/lang/Double");
654 jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;");
656 return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value));
659 jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) {
660 Py_ssize_t size = PyByteArray_Size(value);
661 jbyteArray result = (*env)->NewByteArray(env, (jsize)size);
662 char *bytes = PyByteArray_AsString(value);
664 (*env)->SetByteArrayRegion(env, result, 0, size, bytes);
669 jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) {
670 PyObject *utf16Value = PyUnicode_AsUTF16String(string);
671 Py_ssize_t len = PyBytes_Size(utf16Value) / 2;
672 char *bytes = PyBytes_AsString(utf16Value);
674 // Create Java string, skipping the byte order mark in the beginning
675 jstring result = (*env)->NewString(env, (jchar *)bytes + 1, (jsize)min(len, JAVA_MAXINT) - 1);
677 Py_XDECREF(utf16Value);
682 jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) {
683 Py_ssize_t len = PySequence_Size(seq);
684 jsize jlen = (jsize)min(len, JAVA_MAXINT);
685 jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL);
689 for (i = 0; i < jlen; i++) {
690 PyObject *item = PySequence_GetItem(seq, i);
691 if (PyUnicode_Check(item)) {
692 jstring value = pythonStringAsJavaString(env, item);
694 (*env)->SetObjectArrayElement(env, array, i, value);
698 throwPythonException(env, "List item not a string");
706 jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) {
707 Py_ssize_t len = PySequence_Size(seq);
708 jsize jlen = (jsize)min(len, JAVA_MAXINT);
709 jdoubleArray array = (*env)->NewDoubleArray(env, jlen);
713 for (i = 0; i < jlen; i++) {
714 PyObject *item = PySequence_GetItem(seq, i);
715 if (PyFloat_Check(item)) {
716 jdouble value = PyFloat_AsDouble(item);
718 (*env)->SetDoubleArrayRegion(env, array, i, 1, &value);
722 throwPythonException(env, "List item not a floating point value");
730 jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) {
731 if (PyBool_Check(value))
732 return pythonBoolAsBooleanObject(env, value);
733 else if (PyLong_Check(value))
734 return pythonLongAsLongObject(env, value);
735 else if (PyFloat_Check(value))
736 return pythonFloatAsDoubleObject(env, value);
737 else if (PyUnicode_Check(value))
738 return pythonStringAsJavaString(env, value);
739 else if (PyByteArray_Check(value))
740 return pythonByteArrayAsByteArray(env, value);
741 else if (PyDict_Check(value))
742 return pythonDictionaryAsMap(env, value);
743 else if (hasNumpy && PyArray_Check(value))
744 return pythonArrayAsNDArray(env, (PyArrayObject *)value);
745 else if (PySequence_Check(value))
746 return pythonSequenceAsObjectArray(env, value);
751 jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) {
752 Py_ssize_t len = PySequence_Size(seq);
753 jsize jlen = (jsize)min(len, JAVA_MAXINT);
754 jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL);
758 for (i = 0; i < jlen; i++) {
759 PyObject *item = PySequence_GetItem(seq, i);
760 jobject object = pythonObjectAsObject(env, item);
762 (*env)->SetObjectArrayElement(env, array, i, object);
768 jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) {
769 Py_ssize_t len = PySequence_Size(seq);
770 jsize jlen = (jsize)min(len, JAVA_MAXINT);
771 jbooleanArray array = (*env)->NewBooleanArray(env, jlen);
775 for (i = 0; i < jlen; i++) {
776 PyObject *item = PySequence_GetItem(seq, i);
777 if (PyBool_Check(item)) {
778 jboolean value = item == Py_True;
780 (*env)->SetBooleanArrayRegion(env, array, i, 1, &value);
784 throwPythonException(env, "List item not a boolean");
792 jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) {
793 Py_ssize_t len = PySequence_Size(seq);
794 jsize jlen = (jsize)min(len, JAVA_MAXINT);
795 jintArray array = (*env)->NewIntArray(env, jlen);
799 for (i = 0; i < jlen; i++) {
800 PyObject *item = PySequence_GetItem(seq, i);
801 if (PyLong_Check(item)) {
802 jint value = PyLong_AsLong(item);
804 (*env)->SetIntArrayRegion(env, array, i, 1, &value);
808 throwPythonException(env, "List item not an integer");
816 jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) {
817 Py_ssize_t len = PySequence_Size(seq);
818 jsize jlen = (jsize)min(len, JAVA_MAXINT);
819 jlongArray array = (*env)->NewLongArray(env, jlen);
823 for (i = 0; i < jlen; i++) {
824 PyObject *item = PySequence_GetItem(seq, i);
825 if (PyLong_Check(item)) {
826 jlong value = PyLong_AsLongLong(item);
828 (*env)->SetLongArrayRegion(env, array, i, 1, &value);
832 throwPythonException(env, "List item not an integer");
840 jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) {
841 jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
842 jmethodID constructor = (*env)->GetMethodID(env, ndarrayClass, "<init>", "([I[D)V");
844 int ndims = PyArray_NDIM(array);
845 npy_intp *dims = PyArray_DIMS(array);
847 npy_intp len = PyArray_Size((PyObject*)array);
848 double *values = (double*)PyArray_DATA(array);
850 jboolean isFortran = PyArray_ISFORTRAN(array) != 0;
854 if (len > JAVA_MAXINT) {
855 throwPythonException(env, "Array too large");
860 jintArray jdims = (*env)->NewIntArray(env, ndims);
861 jdoubleArray jvalues = (*env)->NewDoubleArray(env, (jsize)len);
863 for (i = 0; i < ndims; i++) {
864 jint dim = (jint)dims[i];
865 (*env)->SetIntArrayRegion(env, jdims, i, 1, &dim);
868 if (PyArray_IS_C_CONTIGUOUS(array)) {
869 (*env)->SetDoubleArrayRegion(env, jvalues, 0, (jsize)len, values);
873 npy_intp *strides = PyArray_STRIDES(array);
874 npy_intp *ncont = (npy_intp*)malloc((ndims + 1) * sizeof(npy_intp));
875 nContiguous(0, ndims, strides, dims, ncont);
876 copyDoubleArrayValues(env, jvalues, values, &offset, 0, ndims, strides, dims, ncont);
880 return (*env)->NewObject(env, ndarrayClass, constructor, jdims, jvalues, isFortran);
884 jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) {
885 jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap");
886 jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "<init>", "(I)V");
887 jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
889 Py_ssize_t size = PyDict_Size(dict);
890 jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size);
892 PyObject *key, *value;
895 while (PyDict_Next(dict, &pos, &key, &value)) {
896 jobject keyObject = pythonObjectAsObject(env, key);
897 jobject valueObject = pythonObjectAsObject(env, value);
898 (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject);
904 #define DEF_SETTER(typename, jtype, j2py) \
905 JNIEXPORT void JNICALL \
906 Java_org_simantics_pythonlink_PythonContext_setPython##typename \
908 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, \
912 PyEval_RestoreThread(main_ts); \
913 module = getModule(contextID); \
914 setPythonVariable(module, getPythonString(env, variableName), \
916 PyEval_SaveThread(); \
919 #define getPythonBoolean(env, value) getPythonBool(value)
920 #define getPythonLong(env, value) PyLong_FromLongLong(value)
921 #define getPythonDouble(env, value) PyFloat_FromDouble(value)
923 DEF_SETTER(Boolean, jboolean, getPythonBoolean)
924 DEF_SETTER(BooleanArray, jbooleanArray, getPythonBooleanList)
925 DEF_SETTER(Long, jlong, getPythonLong)
926 DEF_SETTER(IntegerArray, jintArray, getPythonIntegerList)
927 DEF_SETTER(LongArray, jlongArray, getPythonLongList)
928 DEF_SETTER(Double, jdouble, getPythonDouble)
929 DEF_SETTER(FloatArray, jfloatArray, getPythonFloatList)
930 DEF_SETTER(DoubleArray, jdoubleArray, getPythonDoubleList)
931 DEF_SETTER(String, jstring, getPythonString)
932 DEF_SETTER(StringArray, jobjectArray, getPythonStringList)
934 JNIEXPORT void JNICALL
935 Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl(
936 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
939 throwPythonException(env, "Importing numpy failed");
943 PyEval_RestoreThread(main_ts);
945 PyObject *module = getModule(contextID);
946 PyObject *pythonName = getPythonString(env, variableName);
947 PyObject *val = getPythonNDArray(env, value);
949 setPythonVariable(module, pythonName, val);
954 JNIEXPORT void JNICALL
955 Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(
956 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
957 jobject value, jobject binding) {
960 PyEval_RestoreThread(main_ts);
961 module = getModule(contextID);
962 setPythonVariable(module, getPythonString(env, variableName),
963 getPythonObject(env, value, binding));
967 static PyObject *getExceptionMessage(PyObject *exceptionType, PyObject *exception, PyObject *traceback) {
968 PyObject *formatExc = NULL, *args = NULL;
969 PyObject *tracebackModule = PyImport_ImportModule("traceback");
970 if (!tracebackModule) {
974 if (exception && traceback) {
975 formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception");
976 args = PyTuple_Pack(3, exceptionType, exception, traceback);
978 else if (exception) {
979 formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception_only");
980 args = PyTuple_Pack(2, exceptionType, exception);
983 Py_DECREF(tracebackModule);
985 if (formatExc != NULL && args != NULL) {
986 PyObject *result = PyObject_CallObject(formatExc, args);
988 Py_XDECREF(formatExc);
993 Py_XDECREF(formatExc);
998 JNIEXPORT jint JNICALL
999 Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(
1000 JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) {
1001 const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL);
1003 PyEval_RestoreThread(main_ts);
1006 PyObject *module = getModule(contextID);
1010 globals = PyModule_GetDict(module);
1015 PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals);
1017 PyObject *exceptionType = PyErr_Occurred();
1018 if (exceptionType != NULL) {
1019 PyObject *exception, *traceback, *message;
1020 PyErr_Fetch(&exceptionType, &exception, &traceback);
1022 message = getExceptionMessage(exceptionType, exception, traceback);
1023 if (message != NULL) {
1024 PyObject *emptyStr = PyUnicode_FromString("");
1025 PyObject *joined = PyUnicode_Join(emptyStr, message);
1026 char *messageStr = PyUnicode_AsUTF8(joined);
1027 throwPythonException(env, messageStr);
1029 Py_DECREF(emptyStr);
1034 *ty = (PyTypeObject *)exceptionType;
1035 throwPythonException(
1036 env, ty ? ty->tp_name
1037 : "Internal error, null exception type");
1040 Py_XDECREF(exceptionType);
1041 Py_XDECREF(exception);
1042 Py_XDECREF(traceback);
1045 PyEval_SaveThread();
1046 (*env)->ReleaseStringUTFChars(env, statement, utfchars);
1050 return result != NULL ? 0 : 1;
1055 // Returns a borrowed reference.
1056 static PyObject *getPythonValue(
1057 JNIEnv *env, jlong contextID, jstring variableName) {
1058 PyObject *module = getModule(contextID);
1059 PyObject *pythonName = getPythonString(env, variableName);
1060 PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);
1062 Py_DECREF(pythonName);
1063 if (value == NULL) {
1064 throwPythonException(env, "Python variable not found");
1069 #define DEF_GETTER(typename, jtype, check, desc, py2j) \
1070 JNIEXPORT jtype JNICALL \
1071 Java_org_simantics_pythonlink_PythonContext_getPython##typename \
1073 JNIEnv *env, jobject thisObj, jlong contextID, \
1074 jstring variableName) { \
1076 PyEval_RestoreThread(main_ts); \
1078 PyObject *value = getPythonValue(env, contextID, variableName); \
1079 if (value == 0) break; \
1080 if (check(value)) { \
1081 result = py2j(env, value); \
1083 throwPythonException(env, "Python variable not " desc); \
1086 PyEval_SaveThread(); \
1090 #define pythonBoolAsJboolean(env, value) ((value) == Py_True)
1091 #define pythonLongAsJlong(env, value) PyLong_AsLongLong(value)
1092 #define pythonFloatAsJdouble(env, value) PyFloat_AsDouble(value)
1094 DEF_GETTER(String, jstring, PyUnicode_Check, "a string",
1095 pythonStringAsJavaString)
1096 DEF_GETTER(StringArray, jobjectArray, PySequence_Check, "a sequence",
1097 pythonSequenceAsStringArray)
1098 DEF_GETTER(Boolean, jboolean, PyBool_Check, "a Boolean", pythonBoolAsJboolean)
1099 DEF_GETTER(BooleanArray, jbooleanArray, PySequence_Check, "a sequence",
1100 pythonSequenceAsBooleanArray)
1101 DEF_GETTER(Long, jlong, PyLong_Check, "an integer", pythonLongAsJlong)
1102 DEF_GETTER(IntegerArray, jintArray, PySequence_Check, "a sequence",
1103 pythonSequenceAsIntegerArray)
1104 DEF_GETTER(LongArray, jlongArray, PySequence_Check, "a sequence",
1105 pythonSequenceAsLongArray)
1106 DEF_GETTER(Double, jdouble, PyFloat_Check, "a float", pythonFloatAsJdouble)
1107 DEF_GETTER(DoubleArray, jdoubleArray, PySequence_Check, "a sequence",
1108 pythonSequenceAsDoubleArray)
1110 JNIEXPORT jobject JNICALL
1111 Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(
1112 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
1113 jobject result = NULL;
1116 throwPythonException(env, "Importing numpy failed");
1120 PyEval_RestoreThread(main_ts);
1122 PyObject *value = getPythonValue(env, contextID, variableName);
1123 if (value == NULL) break;
1124 if (!PyArray_Check(value)) {
1125 throwPythonException(env, "Python variable not an ndarray");
1126 } else if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) {
1127 throwPythonException(
1128 env, "Only ndarrays of type double are supported");
1130 result = pythonArrayAsNDArray(env, (PyArrayObject *)value);
1133 PyEval_SaveThread();
1137 #define python_anything_goes(value) 1
1139 DEF_GETTER(Variant, jobject, python_anything_goes, "frabjous",
1140 pythonObjectAsObject)
1142 JNIEXPORT jint JNICALL
1143 Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(
1144 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
1146 PyEval_RestoreThread(main_ts);
1148 PyObject *value = getPythonValue(env, contextID, variableName);
1149 if (PyBool_Check(value))
1151 else if (PyLong_Check(value))
1153 else if (PyFloat_Check(value))
1155 else if (PyUnicode_Check(value))
1157 else if (PyByteArray_Check(value))
1159 else if (PyDict_Check(value))
1161 else if (hasNumpy && PyArray_Check(value))
1163 else if (PySequence_Check(value))
1168 PyEval_SaveThread();
1172 JNIEXPORT jobjectArray JNICALL
1173 Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(
1174 JNIEnv *env, jobject thisObj, jlong contextID) {
1175 jobjectArray result = NULL;
1176 PyEval_RestoreThread(main_ts);
1178 PyObject *module = getModule(contextID);
1179 PyObject *dict = PyModule_GetDict(module);
1181 PyObject *keys = PyDict_Keys(dict);
1182 Py_ssize_t size = PyList_Size(keys);
1185 result = (*env)->NewObjectArray(
1186 env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL);
1188 for (i = 0; i < size; i++) {
1189 jstring javaName = pythonStringAsJavaString(
1190 env, PyList_GetItem(keys, i));
1191 (*env)->SetObjectArrayElement(env, result, (jint)i, javaName);
1196 PyEval_SaveThread();
1200 BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1201 //extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1205 case DLL_PROCESS_ATTACH:
1206 // attach to process
1207 // return FALSE to fail DLL load
1210 case DLL_PROCESS_DETACH:
1211 // detach from process
1214 case DLL_THREAD_ATTACH:
1218 case DLL_THREAD_DETACH:
1219 // detach from thread
1222 return TRUE; // succesful