writeToSCL(PyObject *self, PyObject *args)
{
if (currentEnv != NULL && sclWriter != NULL) {
- JNIEnv *env = currentEnv;
-
Py_UNICODE *what;
Py_ssize_t length;
+ JNIEnv *env = currentEnv;
+
if (!PyArg_ParseTuple(args, "u#", &what, &length))
Py_RETURN_NONE;
Py_RETURN_NONE;
}
+static PyObject *
+flushSCL(PyObject *self, PyObject *args)
+{
+ if (currentEnv != NULL && sclWriter != NULL) {
+ JNIEnv *env = currentEnv;
+ PyThreadState *my_ts = PyThreadState_Get();
+ if (my_ts != main_ts) {
+ // TODO: Process calls from other threads
+ Py_RETURN_NONE;
+ }
+
+ {
+ jclass writerClass = (*env)->FindClass(env, WRITER_CLASS);
+ jmethodID flushMethod = (*env)->GetMethodID(env, writerClass, "flush", "()V");
+
+ Py_BEGIN_ALLOW_THREADS
+ (*env)->CallVoidMethod(env, sclWriter, flushMethod);
+ Py_END_ALLOW_THREADS
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
static PyMethodDef sclWriterMethods[] = {
{"write", writeToSCL, METH_VARARGS, "Write something."},
+ {"flush", flushSCL, METH_VARARGS, "Flush output."},
{NULL, NULL, 0, NULL}
};
+JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_initializePython(JNIEnv *env, jobject thisObj, jobject writer) {
+ Py_Initialize();
-JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) {
- char name[16];
+ {
+ static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods, };
+ PyObject *m = PyModule_Create(&moduledef);
- if (!main_ts) {
- Py_Initialize();
+ sclWriter = (*env)->NewGlobalRef(env, writer);
+
+ if (m == NULL) throwException(env, PYTHON_EXCEPTION, "Failed to create SCL writer module");
+
+ PySys_SetObject("stdout", m);
+ PySys_SetObject("stderr", m);
+ }
+
+ hasNumpy = _import_array();
+ hasNumpy = hasNumpy != -1;
- {
- static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods, };
- PyObject *m = PyModule_Create(&moduledef);
+ main_ts = PyEval_SaveThread();
+}
- if (m == NULL) throwException(env, PYTHON_EXCEPTION, "Failed to create SCL writer module");
- PySys_SetObject("stdout", m);
- PySys_SetObject("stderr", m);
- }
+JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) {
+ char name[16];
- hasNumpy = _import_array();
- hasNumpy = hasNumpy != -1;
- main_ts = PyEval_SaveThread();
+ if (!main_ts) {
+ return 0;
}
sprintf(name, "SCL_%d", ++moduleCount);
PyEval_SaveThread();
}
+static PyObject *getExceptionMessage(PyObject *exceptionType, PyObject *exception, PyObject *traceback) {
+ PyObject *formatExc = NULL, *args = NULL;
+ PyObject *tracebackModule = PyImport_ImportModule("traceback");
+ if (!tracebackModule) {
+ return NULL;
+ }
+
+ if (exception && traceback) {
+ formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception");
+ args = PyTuple_Pack(3, exceptionType, exception, traceback);
+ }
+ else if (exception) {
+ formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception_only");
+ args = PyTuple_Pack(2, exceptionType, exception);
+ }
+
+ Py_DECREF(tracebackModule);
+
+ if (formatExc != NULL && args != NULL) {
+ PyObject *result = PyObject_CallObject(formatExc, args);
+ Py_XDECREF(args);
+ Py_XDECREF(formatExc);
+ return result;
+ }
+ else {
+ Py_XDECREF(args);
+ Py_XDECREF(formatExc);
+ return NULL;
+ }
+}
+
JNIEXPORT jint JNICALL
Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(
JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) {
{
PyObject *module = getModule(contextID);
- jclass sclReportingWriterClass = (*env)->FindClass(env, SCL_REPORTING_WRITER_CLASS);
- jmethodID constructor = (*env)->GetMethodID(env, sclReportingWriterClass, "<init>", "()V");
- jmethodID flushMethod = (*env)->GetMethodID(env, sclReportingWriterClass, "flush", "()V");
-
PyObject *globals;
globals = PyModule_GetDict(module);
currentEnv = env;
- if (sclReportingWriterClass && constructor)
- sclWriter = (*env)->NewObject(env, sclReportingWriterClass, constructor);
- else
- sclWriter = NULL;
{
PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals);
PyObject *exceptionType = PyErr_Occurred();
if (exceptionType != NULL) {
- PyObject *exception, *traceback;
+ PyObject *exception, *traceback, *message;
PyErr_Fetch(&exceptionType, &exception, &traceback);
- {
- PyObject *tracebackModule = PyImport_ImportModule("traceback");
- if (tracebackModule != NULL) {
- PyObject *formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception");
- if (formatExc != NULL) {
- PyObject *args = PyTuple_Pack(3, exceptionType, exception, traceback);
- PyObject *message = PyObject_CallObject(formatExc, args);
- if (message != NULL) {
- PyObject *emptyStr = PyUnicode_FromString("");
- PyObject *joined = PyUnicode_Join(emptyStr, message);
- char *messageStr = PyUnicode_AsUTF8(joined);
- throwPythonException(env, messageStr);
- Py_DECREF(joined);
- Py_DECREF(emptyStr);
- Py_DECREF(message);
- }
- else {
- PyTypeObject
- *ty = (PyTypeObject *)exceptionType;
- throwPythonException(
- env, ty ? ty->tp_name
- : "Internal error, null exception type");
- }
- Py_DECREF(args);
- Py_DECREF(formatExc);
- }
- else {
- throwPythonException(env, "Internal error, no format_exc function");
- }
- Py_DECREF(tracebackModule);
- }
- else {
- throwPythonException(env, "Internal error, no traceback module");
- }
+ message = getExceptionMessage(exceptionType, exception, traceback);
+ if (message != NULL) {
+ PyObject *emptyStr = PyUnicode_FromString("");
+ PyObject *joined = PyUnicode_Join(emptyStr, message);
+ char *messageStr = PyUnicode_AsUTF8(joined);
+ throwPythonException(env, messageStr);
+ Py_DECREF(joined);
+ Py_DECREF(emptyStr);
+ Py_DECREF(message);
+ }
+ else {
+ PyTypeObject
+ *ty = (PyTypeObject *)exceptionType;
+ throwPythonException(
+ env, ty ? ty->tp_name
+ : "Internal error, null exception type");
}
+
Py_XDECREF(exceptionType);
Py_XDECREF(exception);
Py_XDECREF(traceback);
PyEval_SaveThread();
(*env)->ReleaseStringUTFChars(env, statement, utfchars);
- if (sclWriter != NULL) {
- (*env)->CallVoidMethod(env, sclWriter, flushMethod);
- }
-
currentEnv = NULL;
- sclWriter = NULL;
return result != NULL ? 0 : 1;
}
-#ifndef __MAIN_H__\r
-#define __MAIN_H__\r
-\r
-#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\r
-#ifdef _DEBUG\r
- #undef _DEBUG\r
- #include <Python.h> //header for system python import; add include paths\r
- #include <numpy/arrayobject.h>\r
- #define _DEBUG 1\r
-#else\r
- #include <Python.h> //header for system python import; add include paths\r
- #include <numpy/arrayobject.h>\r
-#endif\r
-\r
-#include <jni.h> //java connection header\r
-\r
-/* To use this exported function of dll, include this header\r
- * in your project.\r
- */\r
-\r
-#ifdef BUILD_DLL\r
- #define DLL_EXPORT __declspec(dllexport)\r
-#else\r
- #define DLL_EXPORT __declspec(dllimport)\r
-#endif\r
-\r
-\r
-#define JAVA_MAXINT (0x7fffffff)\r
-\r
-#define PYTHON_EXCEPTION "org/simantics/pythonlink/PythonException"\r
-#define ILLEGAL_ARGUMENT_EXCEPTION "java/lang/IllegalArgumentException"\r
-#define OBJECT_CLASS "java/lang/Object"\r
-#define STRING_CLASS "java/lang/String"\r
-#define MAP_CLASS "java/util/Map"\r
-#define SET_CLASS "java/util/Set"\r
-\r
-#define WRITER_CLASS "java/io/Writer"\r
-#define SCL_REPORTING_WRITER_CLASS "org/simantics/scl/runtime/reporting/SCLReportingWriter"\r
-\r
-#define PACKAGE_PREFIX "org/simantics/pythonlink/"\r
-\r
-#define NDARRAY_CLASS (PACKAGE_PREFIX "NDArray")\r
-\r
-#define VARIANT_CLASS "org/simantics/databoard/binding/mutable/Variant"\r
-#define BINDINGS_CLASS "org/simantics/databoard/Bindings"\r
-#define BINDING_CLASS "org/simantics/databoard/binding/Binding"\r
-#define DATATYPE_CLASS "org/simantics/databoard/type/Datatype"\r
-\r
-#define BOOLEANTYPE_CLASS "org/simantics/databoard/type/BooleanType"\r
-#define BYTETYPE_CLASS "org/simantics/databoard/type/ByteType"\r
-#define INTEGERTYPE_CLASS "org/simantics/databoard/type/IntegerType"\r
-#define LONGTYPE_CLASS "org/simantics/databoard/type/LongType"\r
-#define FLOATTYPE_CLASS "org/simantics/databoard/type/FloatType"\r
-#define DOUBLETYPE_CLASS "org/simantics/databoard/type/DoubleType"\r
-#define STRINGTYPE_CLASS "org/simantics/databoard/type/StringType"\r
-#define RECORDTYPE_CLASS "org/simantics/databoard/type/RecordType"\r
-#define ARRAYTYPE_CLASS "org/simantics/databoard/type/ArrayType"\r
-#define MAPTYPE_CLASS "org/simantics/databoard/type/MapType"\r
-#define OPTIONALTYPE_CLASS "org/simantics/databoard/type/OptionalType"\r
-#define UNIONTYPE_CLASS "org/simantics/databoard/type/UnionType"\r
-#define VARIANTTYPE_CLASS "org/simantics/databoard/type/VariantType"\r
-\r
-#define BOOLEANBINDING_CLASS "org/simantics/databoard/binding/BooleanBinding"\r
-#define BYTEBINDING_CLASS "org/simantics/databoard/binding/ByteBinding"\r
-#define INTEGERBINDING_CLASS "org/simantics/databoard/binding/IntegerBinding"\r
-#define LONGBINDING_CLASS "org/simantics/databoard/binding/LongBinding"\r
-#define FLOATBINDING_CLASS "org/simantics/databoard/binding/FloatBinding"\r
-#define DOUBLEBINDING_CLASS "org/simantics/databoard/binding/DoubleBinding"\r
-#define STRINGBINDING_CLASS "org/simantics/databoard/binding/StringBinding"\r
-#define RECORDBINDING_CLASS "org/simantics/databoard/binding/RecordBinding"\r
-#define ARRAYBINDING_CLASS "org/simantics/databoard/binding/ArrayBinding"\r
-#define MAPBINDING_CLASS "org/simantics/databoard/binding/MapBinding"\r
-#define OPTIONALBINDING_CLASS "org/simantics/databoard/binding/OptionalBinding"\r
-#define UNIONBINDING_CLASS "org/simantics/databoard/binding/UnionBinding"\r
-#define VARIANTBINDING_CLASS "org/simantics/databoard/binding/VariantBinding"\r
-\r
-#define COMPONENT_CLASS "org/simantics/databoard/type/Component"\r
-#define TAGGEDOBJECT_CLASS "org/simantics/databoard/binding/mutable/TaggedObject"\r
-\r
-PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value);\r
-PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value);\r
-PyObject *getPythonIntegerList(JNIEnv *env, jintArray value);\r
-PyObject *getPythonLongList(JNIEnv *env, jlongArray value);\r
-PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value);\r
-PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value);\r
-\r
-PyObject *getPythonObject(JNIEnv *env, jobject object, jobject binding);\r
-\r
-PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding);\r
-PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding);\r
-PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding);\r
-PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding);\r
-PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding);\r
-PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding);\r
-PyObject *getPythonRecordObject(JNIEnv *env, jobjectArray object, jobject binding);\r
-PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding);\r
-PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding);\r
-PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding);\r
-PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding);\r
-PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding);\r
-\r
-void setPythonVariable(PyObject *module, PyObject *name, PyObject *value);\r
-\r
-jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value);\r
-jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value);\r
-jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value);\r
-jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value);\r
-jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string);\r
-jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq);\r
-jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *list);\r
-jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *list);\r
-jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *list);\r
-jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *list);\r
-jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict);\r
-jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array);\r
-jobject pythonObjectAsObject(JNIEnv *env, PyObject *value);\r
-\r
-#endif // __MAIN_H__\r
+#ifndef __MAIN_H__
+#define __MAIN_H__
+
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+#ifdef _DEBUG
+ #undef _DEBUG
+ #include <Python.h> //header for system python import; add include paths
+ #include <numpy/arrayobject.h>
+ #define _DEBUG 1
+#else
+ #include <Python.h> //header for system python import; add include paths
+ #include <numpy/arrayobject.h>
+#endif
+
+#include <jni.h> //java connection header
+
+/* To use this exported function of dll, include this header
+ * in your project.
+ */
+
+#ifdef BUILD_DLL
+ #define DLL_EXPORT __declspec(dllexport)
+#else
+ #define DLL_EXPORT __declspec(dllimport)
+#endif
+
+
+#define JAVA_MAXINT (0x7fffffff)
+
+#define PYTHON_EXCEPTION "org/simantics/pythonlink/PythonException"
+#define ILLEGAL_ARGUMENT_EXCEPTION "java/lang/IllegalArgumentException"
+#define OBJECT_CLASS "java/lang/Object"
+#define STRING_CLASS "java/lang/String"
+#define MAP_CLASS "java/util/Map"
+#define SET_CLASS "java/util/Set"
+
+#define WRITER_CLASS "java/io/Writer"
+
+#define PACKAGE_PREFIX "org/simantics/pythonlink/"
+
+#define NDARRAY_CLASS (PACKAGE_PREFIX "NDArray")
+
+#define VARIANT_CLASS "org/simantics/databoard/binding/mutable/Variant"
+#define BINDINGS_CLASS "org/simantics/databoard/Bindings"
+#define BINDING_CLASS "org/simantics/databoard/binding/Binding"
+#define DATATYPE_CLASS "org/simantics/databoard/type/Datatype"
+
+#define BOOLEANTYPE_CLASS "org/simantics/databoard/type/BooleanType"
+#define BYTETYPE_CLASS "org/simantics/databoard/type/ByteType"
+#define INTEGERTYPE_CLASS "org/simantics/databoard/type/IntegerType"
+#define LONGTYPE_CLASS "org/simantics/databoard/type/LongType"
+#define FLOATTYPE_CLASS "org/simantics/databoard/type/FloatType"
+#define DOUBLETYPE_CLASS "org/simantics/databoard/type/DoubleType"
+#define STRINGTYPE_CLASS "org/simantics/databoard/type/StringType"
+#define RECORDTYPE_CLASS "org/simantics/databoard/type/RecordType"
+#define ARRAYTYPE_CLASS "org/simantics/databoard/type/ArrayType"
+#define MAPTYPE_CLASS "org/simantics/databoard/type/MapType"
+#define OPTIONALTYPE_CLASS "org/simantics/databoard/type/OptionalType"
+#define UNIONTYPE_CLASS "org/simantics/databoard/type/UnionType"
+#define VARIANTTYPE_CLASS "org/simantics/databoard/type/VariantType"
+
+#define BOOLEANBINDING_CLASS "org/simantics/databoard/binding/BooleanBinding"
+#define BYTEBINDING_CLASS "org/simantics/databoard/binding/ByteBinding"
+#define INTEGERBINDING_CLASS "org/simantics/databoard/binding/IntegerBinding"
+#define LONGBINDING_CLASS "org/simantics/databoard/binding/LongBinding"
+#define FLOATBINDING_CLASS "org/simantics/databoard/binding/FloatBinding"
+#define DOUBLEBINDING_CLASS "org/simantics/databoard/binding/DoubleBinding"
+#define STRINGBINDING_CLASS "org/simantics/databoard/binding/StringBinding"
+#define RECORDBINDING_CLASS "org/simantics/databoard/binding/RecordBinding"
+#define ARRAYBINDING_CLASS "org/simantics/databoard/binding/ArrayBinding"
+#define MAPBINDING_CLASS "org/simantics/databoard/binding/MapBinding"
+#define OPTIONALBINDING_CLASS "org/simantics/databoard/binding/OptionalBinding"
+#define UNIONBINDING_CLASS "org/simantics/databoard/binding/UnionBinding"
+#define VARIANTBINDING_CLASS "org/simantics/databoard/binding/VariantBinding"
+
+#define COMPONENT_CLASS "org/simantics/databoard/type/Component"
+#define TAGGEDOBJECT_CLASS "org/simantics/databoard/binding/mutable/TaggedObject"
+
+PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value);
+PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value);
+PyObject *getPythonIntegerList(JNIEnv *env, jintArray value);
+PyObject *getPythonLongList(JNIEnv *env, jlongArray value);
+PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value);
+PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value);
+
+PyObject *getPythonObject(JNIEnv *env, jobject object, jobject binding);
+
+PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding);
+PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding);
+PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding);
+PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding);
+PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding);
+PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding);
+PyObject *getPythonRecordObject(JNIEnv *env, jobjectArray object, jobject binding);
+PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding);
+PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding);
+PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding);
+PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding);
+PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding);
+
+void setPythonVariable(PyObject *module, PyObject *name, PyObject *value);
+
+jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value);
+jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value);
+jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value);
+jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value);
+jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string);
+jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq);
+jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *list);
+jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *list);
+jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *list);
+jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *list);
+jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict);
+jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array);
+jobject pythonObjectAsObject(JNIEnv *env, PyObject *value);
+
+#endif // __MAIN_H__
package org.simantics.pythonlink;
import java.io.Closeable;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import org.simantics.databoard.binding.error.BindingException;
import org.simantics.databoard.binding.mutable.Variant;
import org.simantics.scl.runtime.SCLContext;
-import org.simantics.scl.runtime.reporting.SCLReportingHandler;
public class PythonContext implements Closeable {
- private long contextID;
+ protected static final String PYTHON_SCL_WRITER = "python.scl.writer";
+ //TODO Replace with a count of open contexts and call Py_Finalize when the last one closes.
+ private static Boolean isPyInitialized = false;
+
+ // A writer that is called by the sys.stdout and sys.stderr streams in Python
+ private static final Writer pythonWriter = new Writer() {
+ Writer defaultWriter = new OutputStreamWriter(System.out);
+
+ @Override
+ public void close() throws IOException {
+ throw new IllegalStateException("This writer should never be closed!");
+ }
+
+ @Override
+ public void flush() throws IOException {
+ Writer writer = getPythonWriter();
+ synchronized (writer) {
+ writer.flush();
+ }
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ Writer writer = getPythonWriter();
+ synchronized (writer) {
+ writer.write(cbuf, off, len);
+ }
+ }
+
+ // Get a thread-specific Writer instance
+ private Writer getPythonWriter() {
+ SCLContext sclContext = SCLContext.getCurrent();
+ Writer writer = (Writer) sclContext.get(PYTHON_SCL_WRITER);
+ return writer != null ? writer : defaultWriter;
+ }
+ };
- public interface Listener {
+ private static synchronized void ensurePythonInit() {
+ if (!isPyInitialized) {
+ execute(() -> initializePython(pythonWriter));
+ isPyInitialized = true;
+ }
+ }
+
+ public interface Listener {
void updated(String variableName);
void closed();
}
- static ExecutorService pythonExecutor = Executors.newSingleThreadExecutor();
-
Set<Listener> listeners = new HashSet<>();
public enum VariableType {
static Pattern namePattern = Pattern.compile("([a-zA-Z_][a-zA-Z_0-9]*)");
- PythonContext() {
+ // Really a C pointer.
+ private long contextID;
+
+ PythonContext() {
+ ensurePythonInit();
contextID = execute(() -> createContextImpl());
+ if (contextID == 0) {
+ throw new PythonException("Python initialization has failed");
+ }
}
public void addListener(Listener listener) {
}
@Override
- public void close() {
+ public synchronized void close() {
long id = contextID;
contextID = 0;
if (id != 0) execute(() -> deleteContextImpl(id));
close();
}
- public void executePythonStatement(String statement) {
+ public void executePythonStatement(String statement, Writer writer) {
SCLContext sclContext = SCLContext.getCurrent();
execute(() -> {
SCLContext.push(sclContext);
- executePythonStatementImpl( contextID, statement );
+ Writer oldWriter = (Writer) sclContext.put(PYTHON_SCL_WRITER, writer);
+ try {
+ executePythonStatementImpl( contextID, statement );
+ pythonWriter.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (oldWriter != null) {
+ sclContext.put(PYTHON_SCL_WRITER, oldWriter);
+ }
+ else {
+ sclContext.remove(PYTHON_SCL_WRITER);
+ }
+ }
SCLContext.pop();
});
for (Listener l : listeners) { l.updated(null); }
}
+ public void executePythonStatement(String statement) {
+ executePythonStatement(statement, new SCLReportingWriter());
+ }
+
// Setters
public void setPythonBooleanVariable(String variableName, boolean value) {
throw new IllegalArgumentException("Invalid Python variable name " + variableName);
}
- static void execute(Runnable job) {
+ static final ExecutorService pythonExecutor = Executors.newSingleThreadExecutor();
+
+ static void execute(Runnable job) {
try {
pythonExecutor.submit(job).get();
} catch (InterruptedException | ExecutionException e) {
}
// Native function declarations
+ private static native void initializePython(Writer writer);
+
private static native long createContextImpl();
private static native void deleteContextImpl(long contextID);
--- /dev/null
+package org.simantics.pythonlink;
+
+import java.io.Writer;
+
+import org.simantics.scl.runtime.reporting.SCLReporting;
+
+public class SCLReportingWriter extends Writer {
+
+ StringBuilder builder = null;
+
+ public SCLReportingWriter() {
+ builder = new StringBuilder();
+ }
+
+ @Override
+ public void close() {
+ flush();
+ }
+
+ @Override
+ public void flush() {
+ if (builder.length() > 0) {
+ SCLReporting.print(builder.toString());
+ builder.setLength(0);
+ }
+ }
+
+ @Override
+ public void write(char[] buf, int off, int len) {
+ if (len == 0) return;
+
+ if (len < 0) throw new IllegalArgumentException("Negative buffer region length");
+ if (off < 0) throw new IllegalArgumentException("Negative buffer region offset");
+ if (off + len > buf.length) throw new IllegalArgumentException("Buffer region overflow");
+
+ for (int i = 0; i < len; i++) {
+ if (buf[off + i] == '\n') {
+ SCLReporting.print(builder.toString());
+ builder.setLength(0);
+ }
+ else {
+ builder.append(buf[off + i]);
+ }
+ }
+ }
+}