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) {
51 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);
78 static PyMethodDef sclWriterMethods[] = {
79 {"write", writeToSCL, METH_VARARGS, "Write something."},
84 JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) {
91 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods, };
92 PyObject *m = PyModule_Create(&moduledef);
94 if (m == NULL) throwException(env, PYTHON_EXCEPTION, "Failed to create SCL writer module");
95 PySys_SetObject("stdout", m);
96 PySys_SetObject("stderr", m);
99 hasNumpy = _import_array();
100 hasNumpy = hasNumpy != -1;
101 main_ts = PyEval_SaveThread();
104 sprintf(name, "SCL_%d", ++moduleCount);
106 PyEval_RestoreThread(main_ts);
109 PyModuleDef *modDef = malloc(sizeof(PyModuleDef));
110 memset(modDef, 0, sizeof(PyModuleDef));
111 modDef->m_name = strdup(name);
112 modDef->m_doc = NULL;
115 module = PyModule_Create(modDef);
117 PyState_AddModule(module, modDef);
120 PyObject *builtin = PyImport_AddModule("builtins");
121 PyObject *dict = PyModule_GetDict(module);
122 PyDict_SetItemString(dict, "__builtin__", builtin);
123 PyDict_SetItemString(dict, "__builtins__", builtin);
126 return (jlong)modDef;
131 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) {
132 PyModuleDef *modDef = (PyModuleDef*)contextID;
134 PyEval_RestoreThread(main_ts);
135 module = PyState_FindModule(modDef);
137 PyState_RemoveModule(modDef);
138 free((char*)modDef->m_name);
143 PyObject *getPythonBool(jboolean value) {
152 PyObject *getPythonString(JNIEnv *env, jstring string) {
153 jsize len = (*env)->GetStringLength(env, string);
154 const jchar *chars = (*env)->GetStringChars(env, string, NULL);
156 PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
158 (*env)->ReleaseStringChars(env, string, chars);
162 PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) {
163 jsize nitems = (*env)->GetArrayLength(env, value);
164 jint *values = (*env)->GetIntArrayElements(env, value, NULL);
165 jclass stringClass = (*env)->FindClass(env, STRING_CLASS);
168 PyObject *result = PyList_New(nitems);
169 for (i = 0; i < nitems; i++) {
170 jobject item = (*env)->GetObjectArrayElement(env, value, i);
171 if (item != NULL && (*env)->IsInstanceOf(env, item, stringClass)) {
172 PyList_SetItem(result, i, getPythonString(env, (jstring)item));
175 PyList_SetItem(result, i, Py_None);
179 (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
183 PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) {
184 jsize nitems = (*env)->GetArrayLength(env, value);
185 jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL);
188 PyObject *result = PyList_New(nitems);
189 for (i = 0; i < nitems; i++) {
190 PyList_SetItem(result, i, getPythonBool(values[i]));
193 (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT);
197 PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) {
198 jint len = (*env)->GetArrayLength(env, value);
199 jbyte *values = (*env)->GetByteArrayElements(env, value, NULL);
201 PyObject *result = PyByteArray_FromStringAndSize(values, len);
203 (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT);
207 PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) {
208 jsize nitems = (*env)->GetArrayLength(env, value);
209 jint *values = (*env)->GetIntArrayElements(env, value, NULL);
212 PyObject *result = PyList_New(nitems);
213 for (i = 0; i < nitems; i++) {
214 PyList_SetItem(result, i, PyLong_FromLong(values[i]));
217 (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
221 PyObject *getPythonLongList(JNIEnv *env, jlongArray value) {
222 jsize nitems = (*env)->GetArrayLength(env, value);
223 jlong *values = (*env)->GetLongArrayElements(env, value, NULL);
226 PyObject *result = PyList_New(nitems);
227 for (i = 0; i < nitems; i++) {
228 PyList_SetItem(result, i, PyLong_FromLongLong(values[i]));
231 (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT);
235 PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) {
236 jsize nitems = (*env)->GetArrayLength(env, value);
237 float *values = (*env)->GetFloatArrayElements(env, value, NULL);
240 PyObject *result = PyList_New(nitems);
241 for (i = 0; i < nitems; i++) {
242 PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i]));
245 (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT);
249 PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) {
250 jsize nitems = (*env)->GetArrayLength(env, value);
251 double *values = (*env)->GetDoubleArrayElements(env, value, NULL);
254 PyObject *result = PyList_New(nitems);
255 for (i = 0; i < nitems; i++) {
256 PyList_SetItem(result, i, PyFloat_FromDouble(values[i]));
259 (*env)->ReleaseDoubleArrayElements(env, value, values, JNI_ABORT);
263 PyObject *getPythonNDArray(JNIEnv *env, jobject value) {
264 jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
265 jmethodID dimsMethod = (*env)->GetMethodID(env, ndarrayClass, "dims", "()[I");
266 jmethodID getValuesMethod = (*env)->GetMethodID(env, ndarrayClass, "getValues", "()[D");
268 jintArray jdims = (*env)->CallObjectMethod(env, value, dimsMethod);
269 jsize ndims = (*env)->GetArrayLength(env, jdims);
270 jint *dims = (*env)->GetIntArrayElements(env, jdims, NULL);
272 jdoubleArray jvalues = (*env)->CallObjectMethod(env, value, getValuesMethod);
273 jsize len = (*env)->GetArrayLength(env, jvalues);
274 jdouble *values = (*env)->GetDoubleArrayElements(env, jvalues, NULL);
276 npy_intp *pyDims = (npy_intp*)malloc(ndims * sizeof(npy_intp));
278 jint i, nelem = ndims > 0 ? 1 : 0;
279 for (i = 0; i < ndims; i++) {
284 len = min(len, nelem);
287 PyObject *array = PyArray_EMPTY(ndims, pyDims, NPY_DOUBLE, 0);
288 double *data = (double *)PyArray_DATA((PyArrayObject*)array);
290 memcpy(data, values, len * sizeof(double));
294 (*env)->ReleaseDoubleArrayElements(env, jvalues, values, JNI_ABORT);
295 (*env)->ReleaseIntArrayElements(env, jdims, dims, JNI_ABORT);
301 PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) {
302 jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
303 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z");
305 jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object);
306 return getPythonBool(bvalue);
309 PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) {
310 jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS);
311 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B");
313 jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object);
314 return PyLong_FromLong(v);
317 PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) {
318 jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS);
319 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I");
321 jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object);
322 return PyLong_FromLong(v);
325 PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) {
326 jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS);
327 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J");
329 jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object);
330 return PyLong_FromLongLong(v);
333 PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) {
334 jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS);
335 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F");
337 jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object);
338 return PyFloat_FromDouble(v);
341 PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) {
342 jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
343 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D");
345 jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object);
346 return PyFloat_FromDouble(v);
349 PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) {
350 jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS);
351 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";");
353 jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
354 jsize len = (*env)->GetStringLength(env, string);
355 const jchar *chars = (*env)->GetStringChars(env, string, NULL);
357 PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
359 (*env)->ReleaseStringChars(env, string, chars);
363 PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) {
364 jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS);
365 jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
366 jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
367 jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
369 jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS);
370 jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";");
371 jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I");
373 jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
374 jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
376 jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
377 jint n = (*env)->CallIntMethod(env, type, getComponentCount);
380 PyObject *result = PyDict_New();
381 for (i = 0; i < n; i++) {
382 jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i);
383 jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField);
384 jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i);
385 jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i);
387 PyObject *item = getPythonObject(env, componentObject, componentBinding);
388 PyDict_SetItem(result, getPythonString(env, fieldName), item);
394 PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) {
395 jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS);
396 jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
397 jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
398 jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
400 jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
402 jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
404 PyObject *result = PyList_New(size);
407 for (i = 0; i < size; i++) {
408 jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i);
410 PyList_SetItem(result, i, getPythonObject(env, item, componentBinding));
412 PyList_SetItem(result, i, Py_None);
418 PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) {
419 jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS);
420 jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS);
421 jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";");
422 jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";");
423 jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
424 jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V");
426 jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod);
427 jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod);
429 jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
430 jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL);
431 jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL);
433 PyObject *result = PyDict_New();
436 (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values);
438 for (i = 0; i < size; i++) {
439 jobject key = (*env)->GetObjectArrayElement(env, keys, i);
440 jobject item = (*env)->GetObjectArrayElement(env, values, i);
441 PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding));
444 (*env)->DeleteLocalRef(env, keys);
445 (*env)->DeleteLocalRef(env, values);
450 PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) {
451 jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
452 jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z");
454 jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object);
457 jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
458 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
460 jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
461 jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
463 return getPythonObject(env, value, componentBinding);
470 PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) {
471 jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS);
472 jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
473 jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I");
474 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
475 jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
477 jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS);
478 jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";");
480 jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
481 jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
483 jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object);
484 jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
486 jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
487 jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag);
488 jstring compName = (*env)->GetObjectField(env, typeComponent, nameField);
490 jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag);
492 PyObject *result = PyTuple_New(2);
493 PyTuple_SetItem(result, 0, getPythonString(env, compName));
494 PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding));
499 PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) {
500 jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS);
501 jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
502 jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";");
504 jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object);
505 jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object);
507 return getPythonObject(env, content, contentBinding);
510 PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) {
511 jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
512 jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS);
513 jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS);
514 jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS);
515 jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS);
516 jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
517 jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS);
518 jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS);
519 jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS);
520 jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS);
521 jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
522 jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS);
523 jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS);
528 if ((*env)->IsInstanceOf(env, binding, booleanBinding)) {
529 return getPythonBooleanObject(env, value, binding);
531 else if ((*env)->IsInstanceOf(env, binding, byteBinding)) {
532 return getPythonByteObject(env, value, binding);
534 else if ((*env)->IsInstanceOf(env, binding, integerBinding)) {
535 return getPythonIntegerObject(env, value, binding);
537 else if ((*env)->IsInstanceOf(env, binding, longBinding)) {
538 return getPythonLongObject(env, value, binding);
540 else if ((*env)->IsInstanceOf(env, binding, floatBinding)) {
541 return getPythonFloatObject(env, value, binding);
543 else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) {
544 return getPythonDoubleObject(env, value, binding);
546 else if ((*env)->IsInstanceOf(env, binding, stringBinding)) {
547 return getPythonStringObject(env, value, binding);
549 else if ((*env)->IsInstanceOf(env, binding, recordBinding)) {
550 return getPythonRecordObject(env, value, binding);
552 else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) {
553 return getPythonArrayObject(env, value, binding);
555 else if ((*env)->IsInstanceOf(env, binding, mapBinding)) {
556 return getPythonMapObject(env, value, binding);
558 else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) {
559 return getPythonOptionalObject(env, value, binding);
561 else if ((*env)->IsInstanceOf(env, binding, untionBinding)) {
562 return getPythonUnionObject(env, value, binding);
564 else if ((*env)->IsInstanceOf(env, binding, variantBinding)) {
565 return getPythonVariantObject(env, value, binding);
572 void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) {
574 PyDict_SetItem(PyModule_GetDict(module), name, value);
581 static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {
587 npy_intp n = nContiguous(d+1, nd, strides, dims, ncont);
588 ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0;
593 static void copyDoubleArrayValues(JNIEnv *env, jdoubleArray array, double *data, npy_intp *offset, int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {
595 (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data);
600 for (i = 0; i < dims[d]; i++) {
601 copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont);
606 jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) {
607 jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean");
608 jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;");
610 return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True));
613 jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) {
614 jclass longClass = (*env)->FindClass(env, "java/lang/Long");
615 jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;");
617 return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value));
620 jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) {
621 jclass doubleClass = (*env)->FindClass(env, "java/lang/Double");
622 jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;");
624 return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value));
627 jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) {
628 Py_ssize_t size = PyByteArray_Size(value);
629 jbyteArray result = (*env)->NewByteArray(env, (jsize)size);
630 char *bytes = PyByteArray_AsString(value);
632 (*env)->SetByteArrayRegion(env, result, 0, size, bytes);
637 jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) {
638 PyObject *utf16Value = PyUnicode_AsUTF16String(string);
639 Py_ssize_t len = PyBytes_Size(utf16Value) / 2;
640 char *bytes = PyBytes_AsString(utf16Value);
642 // Create Java string, skipping the byte order mark in the beginning
643 jstring result = (*env)->NewString(env, (jchar *)bytes + 1, (jsize)min(len, JAVA_MAXINT) - 1);
645 Py_XDECREF(utf16Value);
650 jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) {
651 Py_ssize_t len = PySequence_Size(seq);
652 jsize jlen = (jsize)min(len, JAVA_MAXINT);
653 jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL);
657 for (i = 0; i < jlen; i++) {
658 PyObject *item = PySequence_GetItem(seq, i);
659 if (PyUnicode_Check(item)) {
660 jstring value = pythonStringAsJavaString(env, item);
661 (*env)->SetObjectArrayElement(env, array, i, value);
664 throwPythonException(env, "List item not a string");
672 jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) {
673 Py_ssize_t len = PySequence_Size(seq);
674 jsize jlen = (jsize)min(len, JAVA_MAXINT);
675 jdoubleArray array = (*env)->NewDoubleArray(env, jlen);
679 for (i = 0; i < jlen; i++) {
680 PyObject *item = PySequence_GetItem(seq, i);
681 if (PyFloat_Check(item)) {
682 double value = PyFloat_AsDouble(item);
683 (*env)->SetDoubleArrayRegion(env, array, i, 1, &value);
686 throwPythonException(env, "List item not a floating point value");
694 jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) {
695 if (PyBool_Check(value))
696 return pythonBoolAsBooleanObject(env, value);
697 else if (PyLong_Check(value))
698 return pythonLongAsLongObject(env, value);
699 else if (PyFloat_Check(value))
700 return pythonFloatAsDoubleObject(env, value);
701 else if (PyUnicode_Check(value))
702 return pythonStringAsJavaString(env, value);
703 else if (PyByteArray_Check(value))
704 return pythonByteArrayAsByteArray(env, value);
705 else if (PyDict_Check(value))
706 return pythonDictionaryAsMap(env, value);
707 else if (hasNumpy && PyArray_Check(value))
708 return pythonArrayAsNDArray(env, (PyArrayObject *)value);
709 else if (PySequence_Check(value))
710 return pythonSequenceAsObjectArray(env, value);
715 jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) {
716 Py_ssize_t len = PySequence_Size(seq);
717 jsize jlen = (jsize)min(len, JAVA_MAXINT);
718 jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL);
722 for (i = 0; i < jlen; i++) {
723 PyObject *item = PySequence_GetItem(seq, i);
724 jobject object = pythonObjectAsObject(env, item);
725 (*env)->SetObjectArrayElement(env, array, i, object);
731 jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) {
732 Py_ssize_t len = PySequence_Size(seq);
733 jsize jlen = (jsize)min(len, JAVA_MAXINT);
734 jbooleanArray array = (*env)->NewBooleanArray(env, jlen);
738 for (i = 0; i < jlen; i++) {
739 PyObject *item = PySequence_GetItem(seq, i);
740 if (PyBool_Check(item)) {
741 jboolean value = item == Py_True;
742 (*env)->SetBooleanArrayRegion(env, array, i, 1, &value);
745 throwPythonException(env, "List item not a boolean");
753 jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) {
754 Py_ssize_t len = PySequence_Size(seq);
755 jsize jlen = (jsize)min(len, JAVA_MAXINT);
756 jintArray array = (*env)->NewIntArray(env, jlen);
760 for (i = 0; i < jlen; i++) {
761 PyObject *item = PySequence_GetItem(seq, i);
762 if (PyLong_Check(item)) {
763 jint value = PyLong_AsLong(item);
764 (*env)->SetIntArrayRegion(env, array, i, 1, &value);
767 throwPythonException(env, "List item not an integer");
775 jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) {
776 Py_ssize_t len = PySequence_Size(seq);
777 jsize jlen = (jsize)min(len, JAVA_MAXINT);
778 jlongArray array = (*env)->NewLongArray(env, jlen);
782 for (i = 0; i < jlen; i++) {
783 PyObject *item = PySequence_GetItem(seq, i);
784 if (PyLong_Check(item)) {
785 jlong value = PyLong_AsLongLong(item);
786 (*env)->SetLongArrayRegion(env, array, i, 1, &value);
789 throwPythonException(env, "List item not an integer");
797 jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) {
798 jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
799 jmethodID constructor = (*env)->GetMethodID(env, ndarrayClass, "<init>", "([I[D)V");
801 int ndims = PyArray_NDIM(array);
802 npy_intp *dims = PyArray_DIMS(array);
804 npy_intp len = PyArray_Size((PyObject*)array);
805 double *values = (double*)PyArray_DATA(array);
807 jboolean isFortran = PyArray_ISFORTRAN(array) != 0;
811 if (len > JAVA_MAXINT) {
812 throwPythonException(env, "Array too large");
817 jintArray jdims = (*env)->NewIntArray(env, ndims);
818 jdoubleArray jvalues = (*env)->NewDoubleArray(env, (jsize)len);
820 for (i = 0; i < ndims; i++) {
821 jint dim = (jint)dims[i];
822 (*env)->SetIntArrayRegion(env, jdims, i, 1, &dim);
825 if (PyArray_IS_C_CONTIGUOUS(array)) {
826 (*env)->SetDoubleArrayRegion(env, jvalues, 0, (jsize)len, values);
830 npy_intp *strides = PyArray_STRIDES(array);
831 npy_intp *ncont = (npy_intp*)malloc((ndims + 1) * sizeof(npy_intp));
832 nContiguous(0, ndims, strides, dims, ncont);
833 copyDoubleArrayValues(env, jvalues, values, &offset, 0, ndims, strides, dims, ncont);
837 return (*env)->NewObject(env, ndarrayClass, constructor, jdims, jvalues, isFortran);
841 jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) {
842 jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap");
843 jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "<init>", "(I)V");
844 jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
846 Py_ssize_t size = PyDict_Size(dict);
847 jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size);
849 PyObject *key, *value;
852 while (PyDict_Next(dict, &pos, &key, &value)) {
853 jobject keyObject = pythonObjectAsObject(env, key);
854 jobject valueObject = pythonObjectAsObject(env, value);
855 (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject);
861 #define DEF_SETTER(typename, jtype, j2py) \
862 JNIEXPORT void JNICALL \
863 Java_org_simantics_pythonlink_PythonContext_setPython##typename \
865 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, \
869 PyEval_RestoreThread(main_ts); \
870 module = getModule(contextID); \
871 setPythonVariable(module, getPythonString(env, variableName), \
873 PyEval_SaveThread(); \
876 #define getPythonBoolean(env, value) getPythonBool(value)
877 #define getPythonLong(env, value) PyLong_FromLongLong(value)
878 #define getPythonDouble(env, value) PyFloat_FromDouble(value)
880 DEF_SETTER(Boolean, jboolean, getPythonBoolean)
881 DEF_SETTER(BooleanArray, jbooleanArray, getPythonBooleanList)
882 DEF_SETTER(Long, jlong, getPythonLong)
883 DEF_SETTER(IntegerArray, jintArray, getPythonIntegerList)
884 DEF_SETTER(LongArray, jlongArray, getPythonLongList)
885 DEF_SETTER(Double, jdouble, getPythonDouble)
886 DEF_SETTER(FloatArray, jfloatArray, getPythonFloatList)
887 DEF_SETTER(DoubleArray, jdoubleArray, getPythonDoubleList)
888 DEF_SETTER(String, jstring, getPythonString)
889 DEF_SETTER(StringArray, jobjectArray, getPythonStringList)
891 JNIEXPORT void JNICALL
892 Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl(
893 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
896 throwPythonException(env, "Importing numpy failed");
900 PyEval_RestoreThread(main_ts);
902 PyObject *module = getModule(contextID);
903 PyObject *pythonName = getPythonString(env, variableName);
904 PyObject *val = getPythonNDArray(env, value);
906 setPythonVariable(module, pythonName, val);
911 JNIEXPORT void JNICALL
912 Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(
913 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
914 jobject value, jobject binding) {
917 PyEval_RestoreThread(main_ts);
918 module = getModule(contextID);
919 setPythonVariable(module, getPythonString(env, variableName),
920 getPythonObject(env, value, binding));
924 JNIEXPORT jint JNICALL
925 Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(
926 JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) {
927 const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL);
929 PyEval_RestoreThread(main_ts);
932 PyObject *module = getModule(contextID);
934 jclass sclReportingWriterClass = (*env)->FindClass(env, SCL_REPORTING_WRITER_CLASS);
935 jmethodID constructor = (*env)->GetMethodID(env, sclReportingWriterClass, "<init>", "()V");
936 jmethodID flushMethod = (*env)->GetMethodID(env, sclReportingWriterClass, "flush", "()V");
940 globals = PyModule_GetDict(module);
943 if (sclReportingWriterClass && constructor)
944 sclWriter = (*env)->NewObject(env, sclReportingWriterClass, constructor);
949 PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals);
951 PyObject *exceptionType = PyErr_Occurred();
952 if (exceptionType != NULL) {
953 PyObject *exception, *traceback;
954 PyErr_Fetch(&exceptionType, &exception, &traceback);
957 PyObject *tracebackModule = PyImport_ImportModule("traceback");
958 if (tracebackModule != NULL) {
959 PyObject *formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception");
960 if (formatExc != NULL) {
961 PyObject *args = PyTuple_Pack(3, exceptionType, exception, traceback);
962 PyObject *message = PyObject_CallObject(formatExc, args);
963 if (message != NULL) {
964 PyObject *emptyStr = PyUnicode_FromString("");
965 PyObject *joined = PyUnicode_Join(emptyStr, message);
966 char *messageStr = PyUnicode_AsUTF8(joined);
967 throwPythonException(env, messageStr);
974 *ty = (PyTypeObject *)exceptionType;
975 throwPythonException(
976 env, ty ? ty->tp_name
977 : "Internal error, null exception type");
980 Py_DECREF(formatExc);
983 throwPythonException(env, "Internal error, no format_exc function");
985 Py_DECREF(tracebackModule);
988 throwPythonException(env, "Internal error, no traceback module");
991 Py_XDECREF(exceptionType);
992 Py_XDECREF(exception);
993 Py_XDECREF(traceback);
997 (*env)->ReleaseStringUTFChars(env, statement, utfchars);
999 if (sclWriter != NULL) {
1000 (*env)->CallVoidMethod(env, sclWriter, flushMethod);
1006 return result != NULL ? 0 : 1;
1011 // Returns a borrowed reference.
1012 static PyObject *getPythonValue(
1013 JNIEnv *env, jlong contextID, jstring variableName) {
1014 PyObject *module = getModule(contextID);
1015 PyObject *pythonName = getPythonString(env, variableName);
1016 PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);
1018 Py_DECREF(pythonName);
1019 if (value == NULL) {
1020 throwPythonException(env, "Python variable not found");
1025 #define DEF_GETTER(typename, jtype, check, desc, py2j) \
1026 JNIEXPORT jtype JNICALL \
1027 Java_org_simantics_pythonlink_PythonContext_getPython##typename \
1029 JNIEnv *env, jobject thisObj, jlong contextID, \
1030 jstring variableName) { \
1032 PyEval_RestoreThread(main_ts); \
1034 PyObject *value = getPythonValue(env, contextID, variableName); \
1035 if (value == 0) break; \
1036 if (check(value)) { \
1037 result = py2j(env, value); \
1039 throwPythonException(env, "Python variable not " desc); \
1042 PyEval_SaveThread(); \
1046 #define pythonBoolAsJboolean(env, value) ((value) == Py_True)
1047 #define pythonLongAsJlong(env, value) PyLong_AsLongLong(value)
1048 #define pythonFloatAsJdouble(env, value) PyFloat_AsDouble(value)
1050 DEF_GETTER(String, jstring, PyUnicode_Check, "a string",
1051 pythonStringAsJavaString)
1052 DEF_GETTER(StringArray, jobjectArray, PySequence_Check, "a sequence",
1053 pythonSequenceAsStringArray)
1054 DEF_GETTER(Boolean, jboolean, PyBool_Check, "a Boolean", pythonBoolAsJboolean)
1055 DEF_GETTER(BooleanArray, jbooleanArray, PySequence_Check, "a sequence",
1056 pythonSequenceAsBooleanArray)
1057 DEF_GETTER(Long, jlong, PyLong_Check, "an integer", pythonLongAsJlong)
1058 DEF_GETTER(IntegerArray, jintArray, PySequence_Check, "a sequence",
1059 pythonSequenceAsIntegerArray)
1060 DEF_GETTER(LongArray, jlongArray, PySequence_Check, "a sequence",
1061 pythonSequenceAsLongArray)
1062 DEF_GETTER(Double, jdouble, PyFloat_Check, "a float", pythonFloatAsJdouble)
1063 DEF_GETTER(DoubleArray, jdoubleArray, PySequence_Check, "a sequence",
1064 pythonSequenceAsDoubleArray)
1066 JNIEXPORT jobject JNICALL
1067 Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(
1068 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
1069 jobject result = NULL;
1072 throwPythonException(env, "Importing numpy failed");
1076 PyEval_RestoreThread(main_ts);
1078 PyObject *value = getPythonValue(env, contextID, variableName);
1079 if (value == NULL) break;
1080 if (!PyArray_Check(value)) {
1081 throwPythonException(env, "Python variable not an ndarray");
1082 } else if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) {
1083 throwPythonException(
1084 env, "Only ndarrays of type double are supported");
1086 result = pythonArrayAsNDArray(env, (PyArrayObject *)value);
1089 PyEval_SaveThread();
1093 #define python_anything_goes(value) 1
1095 DEF_GETTER(Variant, jobject, python_anything_goes, "frabjous",
1096 pythonObjectAsObject)
1098 JNIEXPORT jint JNICALL
1099 Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(
1100 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
1102 PyEval_RestoreThread(main_ts);
1104 PyObject *value = getPythonValue(env, contextID, variableName);
1105 if (PyBool_Check(value))
1107 else if (PyLong_Check(value))
1109 else if (PyFloat_Check(value))
1111 else if (PyUnicode_Check(value))
1113 else if (PyByteArray_Check(value))
1115 else if (PyDict_Check(value))
1117 else if (hasNumpy && PyArray_Check(value))
1119 else if (PySequence_Check(value))
1124 PyEval_SaveThread();
1128 JNIEXPORT jobjectArray JNICALL
1129 Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(
1130 JNIEnv *env, jobject thisObj, jlong contextID) {
1131 jobjectArray result = NULL;
1132 PyEval_RestoreThread(main_ts);
1134 PyObject *module = getModule(contextID);
1135 PyObject *dict = PyModule_GetDict(module);
1137 PyObject *keys = PyDict_Keys(dict);
1138 Py_ssize_t size = PyList_Size(keys);
1141 result = (*env)->NewObjectArray(
1142 env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL);
1144 for (i = 0; i < size; i++) {
1145 jstring javaName = pythonStringAsJavaString(
1146 env, PyList_GetItem(keys, i));
1147 (*env)->SetObjectArrayElement(env, result, (jint)i, javaName);
1152 PyEval_SaveThread();
1156 BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1157 //extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1161 case DLL_PROCESS_ATTACH:
1162 // attach to process
1163 // return FALSE to fail DLL load
1166 case DLL_PROCESS_DETACH:
1167 // detach from process
1170 case DLL_THREAD_ATTACH:
1174 case DLL_THREAD_DETACH:
1175 // detach from thread
1178 return TRUE; // succesful