]> gerrit.simantics Code Review - simantics/python.git/blobdiff - org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java
Added support for dynamically typed data access and a Variable interface.
[simantics/python.git] / org.simantics.pythonlink / src / org / simantics / pythonlink / PythonContext.java
index 5341cc233c16c02076e00bbfa8684aa09d14c001..6c96dd3bde8a877e1e2115c4f1686f4101a44200 100644 (file)
@@ -1,21 +1,73 @@
 package org.simantics.pythonlink;\r
 \r
 import java.io.Closeable;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+import java.util.concurrent.Callable;\r
+import java.util.concurrent.ExecutionException;\r
+import java.util.concurrent.ExecutorService;\r
+import java.util.concurrent.Executors;\r
+import java.util.regex.Pattern;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
 \r
 public class PythonContext implements Closeable {\r
     private long contextID;\r
     \r
+    public interface Listener {\r
+       void updated(String variableName);\r
+       void closed();\r
+    }\r
+    \r
+    static ExecutorService pythonExecutor = Executors.newSingleThreadExecutor();\r
+    \r
+    Set<Listener> listeners = new HashSet<>();\r
+    \r
+    public enum VariableType {\r
+       NO_VARIABLE,\r
+       BOOLEAN,\r
+       LONG,\r
+       FLOAT,\r
+       STRING,\r
+       BYTEARRAY,\r
+       DICTIONARY,\r
+       NDARRAY,\r
+       SEQUENCE,\r
+       UNKNOWN\r
+    }\r
+    \r
+    static Pattern namePattern = Pattern.compile("([a-zA-Z_][a-zA-Z_0-9]*)");\r
+    \r
     PythonContext() {\r
         contextID = createContextImpl();\r
     }\r
     \r
+    public void addListener(Listener listener) {\r
+       listeners.add(listener);\r
+    }\r
+    \r
+    public void removeListener(Listener listener) {\r
+               listeners.remove(listener);\r
+    }\r
+    \r
     @Override\r
     public void close() {\r
         long id = contextID;\r
         contextID = 0;\r
         if (id != 0) deleteContextImpl(id);\r
+        \r
+       for (Listener l : listeners) {\r
+               l.closed();\r
+       }\r
     }\r
 \r
+       public boolean isOpen() {\r
+               return contextID != 0;\r
+       }\r
+       \r
     @Override\r
     protected void finalize() throws Throwable {\r
         super.finalize();\r
@@ -23,82 +75,220 @@ public class PythonContext implements Closeable {
     }\r
     \r
     public void executePythonStatement(String statement) {\r
-        executePythonStatementImpl( contextID, statement );\r
+        execute(() -> executePythonStatementImpl( contextID, statement ));\r
+       for (Listener l : listeners) { l.updated(null); }\r
     }\r
 \r
     // Setters\r
     \r
+    public void setPythonBooleanVariable(String variableName, boolean value) {\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonBooleanVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
+    }\r
+\r
     public void setPythonIntegerVariable(String variableName, int value) {\r
-        setPythonIntegerVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonLongVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
+    }\r
+    public void setPythonLongVariable(String variableName, long value) {\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonLongVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
     public void setPythonDoubleVariable(String variableName, double value) {\r
-        setPythonDoubleVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonDoubleVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
     public void setPythonStringVariable(String variableName, String value) {\r
-        setPythonStringVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonStringVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
     \r
+    public void setPythonBooleanArrayVariable(String variableName, boolean[] value) {\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonBooleanArrayVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
+    }\r
     public void setPythonIntegerArrayVariable(String variableName, int[] value) {\r
-        setPythonIntegerArrayVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonIntegerArrayVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
+    }\r
+    public void setPythonLongArrayVariable(String variableName, long[] value) {\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonLongArrayVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
     public void setPythonDoubleArrayVariable(String variableName, double[] value) {\r
-        setPythonDoubleArrayVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonDoubleArrayVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
     public void setPythonStringArrayVariable(String variableName, String[] value) {\r
-        setPythonStringArrayVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonStringArrayVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
 \r
     // Getters\r
     \r
+    public boolean getPythonBooleanVariable(String variableName) {\r
+        checkValidName(variableName);\r
+        return getPythonBooleanVariableImpl(contextID, variableName);\r
+    }\r
     public int getPythonIntegerVariable(String variableName) {\r
-        return getPythonIntegerVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+       long value = execute(() -> getPythonLongVariableImpl(contextID, variableName));\r
+       if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE)\r
+               throw new RuntimeException("Python value not in integer range");\r
+        return (int) value;\r
+    }\r
+    public long getPythonLongVariable(String variableName) {\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonLongVariableImpl(contextID, variableName));\r
     }\r
     public double getPythonDoubleVariable(String variableName) {\r
-        return getPythonDoubleVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonDoubleVariableImpl(contextID, variableName));\r
     }\r
     public String getPythonStringVariable(String variableName) {\r
-        return getPythonStringVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonStringVariableImpl(contextID, variableName));\r
     }\r
     \r
+    public boolean[] getPythonBooleanArrayVariable(String variableName) {\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonBooleanArrayVariableImpl(contextID, variableName));\r
+    }\r
     public int[] getPythonIntegerArrayVariable(String variableName) {\r
-        return getPythonIntegerArrayVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonIntegerArrayVariableImpl(contextID, variableName));\r
+    }\r
+    public long[] getPythonLongArrayVariable(String variableName) {\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonLongArrayVariableImpl(contextID, variableName));\r
     }\r
     public double[] getPythonDoubleArrayVariable(String variableName) {\r
-        return getPythonDoubleArrayVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonDoubleArrayVariableImpl(contextID, variableName));\r
     }\r
     public String[] getPythonStringArrayVariable(String variableName) {\r
-        return getPythonStringArrayVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonStringArrayVariableImpl(contextID, variableName));\r
     }\r
     \r
     public void setPythonNDArrayVariable(String variableName, NDArray value) {\r
-        setPythonNDArrayVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonNDArrayVariableImpl(contextID, variableName, value));\r
     }\r
     public NDArray getPythonNDArrayVariable(String variableName) {\r
-        return getPythonNDArrayVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonNDArrayVariableImpl(contextID, variableName));\r
     }\r
 \r
+    public Object getPythonVariantVariable(String variableName, Binding binding) {\r
+        checkValidName(variableName);\r
+       Object result = execute(() -> getPythonVariantVariableImpl(contextID, variableName));\r
+       try {\r
+                       return Bindings.OBJECT.getContent(result, binding);\r
+               } catch (BindingException e) {\r
+                       throw new RuntimeException(e);\r
+               }\r
+    }\r
+    \r
+    public Variant getPythonVariantVariable(String variableName) {\r
+        checkValidName(variableName);\r
+       return Variant.ofInstance(execute(() -> getPythonVariantVariableImpl(contextID, variableName)));\r
+    }\r
+\r
+    public void setPythonVariantVariable(String variableName, Variant value) {\r
+       setPythonVariantVariable(variableName, value.getValue(), value.getBinding());\r
+    }\r
+    \r
+    public void setPythonVariantVariable(String variableName, Object value, Binding binding) {\r
+        checkValidName(variableName);\r
+        if (!binding.isInstance(value)) throw new IllegalArgumentException("Invalid object binding");\r
+        \r
+        execute(() -> setPythonVariantVariableImpl(contextID, variableName, value, binding));\r
+        \r
+       for (Listener l : listeners) { l.updated(variableName); }\r
+    }\r
+    \r
+    public VariableType getPythonVariableType(String variableName) {\r
+        checkValidName(variableName);\r
+       int code = execute(() -> getPythonVariableTypeImpl(contextID, variableName));\r
+       \r
+       VariableType[] values = VariableType.values();\r
+       if (code < 0 || code >= values.length)\r
+               return VariableType.UNKNOWN;\r
+       \r
+       return values[code];\r
+    }\r
+    \r
+    public String[] getPythonVariableNames() {\r
+       return execute(() -> getPythonVariableNamesImpl(contextID));\r
+    }\r
+     \r
+    private static void checkValidName(String variableName) {\r
+        if (!namePattern.matcher(variableName).matches())\r
+            throw new IllegalArgumentException("Invalid Python variable name " + variableName);\r
+    }\r
+    \r
+    static void execute(Runnable job) {\r
+        try {\r
+            pythonExecutor.submit(job).get();\r
+        } catch (InterruptedException | ExecutionException e) {\r
+            throw new RuntimeException(e);\r
+        }\r
+    }\r
+    \r
+    static <V> V execute(Callable<V> job) {\r
+        try {\r
+            return pythonExecutor.submit(job).get();\r
+        } catch (InterruptedException | ExecutionException e) {\r
+            throw new RuntimeException(e);\r
+        }\r
+    }\r
+    \r
     // Native function declarations\r
     private static native long createContextImpl();\r
     private static native void deleteContextImpl(long contextID);\r
     \r
     private static native int executePythonStatementImpl(long contextID, String statement);\r
     \r
-    private static native void setPythonIntegerVariableImpl(long contextID, String variableName, int value);\r
+    private static native void setPythonBooleanVariableImpl(long contextID, String variableName, boolean value);\r
+    private static native void setPythonLongVariableImpl(long contextID, String variableName, long value);\r
     private static native void setPythonDoubleVariableImpl(long contextID, String variableName, double value);\r
     private static native void setPythonStringVariableImpl(long contextID, String variableName, String value);\r
     \r
+    private static native void setPythonBooleanArrayVariableImpl(long contextID, String variableName, boolean[] value);\r
     private static native void setPythonIntegerArrayVariableImpl(long contextID, String variableName, int[] value);\r
+    private static native void setPythonLongArrayVariableImpl(long contextID, String variableName, long[] value);\r
     private static native void setPythonDoubleArrayVariableImpl(long contextID, String variableName, double[] value);\r
     private static native void setPythonStringArrayVariableImpl(long contextID, String variableName, String[] value);\r
     \r
-    private static native int getPythonIntegerVariableImpl(long contextID, String variableName);\r
+    private static native boolean getPythonBooleanVariableImpl(long contextID, String variableName);\r
+    private static native long getPythonLongVariableImpl(long contextID, String variableName);\r
     private static native double getPythonDoubleVariableImpl(long contextID, String variableName);\r
     private static native String getPythonStringVariableImpl(long contextID, String variableName);\r
     \r
+    private static native boolean[] getPythonBooleanArrayVariableImpl(long contextID, String variableName);\r
+    private static native long[] getPythonLongArrayVariableImpl(long contextID, String variableName);\r
     private static native int[] getPythonIntegerArrayVariableImpl(long contextID, String variableName);\r
     private static native double[] getPythonDoubleArrayVariableImpl(long contextID, String variableName);\r
     private static native String[] getPythonStringArrayVariableImpl(long contextID, String variableName);\r
     \r
     private static native void setPythonNDArrayVariableImpl(long contextID, String variableName, NDArray value);\r
     private static native NDArray getPythonNDArrayVariableImpl(long contextID, String variableName);\r
+    \r
+    private static native void setPythonVariantVariableImpl(long contextID, String variableName, Object value, Binding binding);\r
+    private static native Object getPythonVariantVariableImpl(long contextID, String variableName);\r
+    \r
+    private static native int getPythonVariableTypeImpl(long contextID, String variableName);\r
+    \r
+    private static native String[] getPythonVariableNamesImpl(long contextID);\r
 }\r