]> git.basschouten.com Git - openhab-addons.git/commitdiff
Add Jython Scripting (#9404)
authorWouter Born <github@maindrain.net>
Thu, 17 Dec 2020 19:24:43 +0000 (20:24 +0100)
committerGitHub <noreply@github.com>
Thu, 17 Dec 2020 19:24:43 +0000 (11:24 -0800)
* Add Jython Scripting

Also-by: Scott Rushworth <openhab@5iver.com>
Signed-off-by: Wouter Born <github@maindrain.net>
CODEOWNERS
bom/openhab-addons/pom.xml
bundles/org.openhab.automation.jythonscripting/NOTICE [new file with mode: 0644]
bundles/org.openhab.automation.jythonscripting/README.md [new file with mode: 0644]
bundles/org.openhab.automation.jythonscripting/pom.xml [new file with mode: 0644]
bundles/org.openhab.automation.jythonscripting/src/main/feature/feature.xml [new file with mode: 0755]
bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/JythonScriptEngineFactory.java [new file with mode: 0755]
bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/package-info.java [new file with mode: 0644]
bundles/pom.xml
pom.xml

index 3a06e0588bec2d6d0b62081a9e295d11f81306ed..96f873cd0c5c0b55f36d3fe4ce68155d02b40d69 100644 (file)
@@ -6,6 +6,7 @@
 
 # Add-on maintainers:
 /bundles/org.openhab.automation.groovyscripting/ @wborn
+/bundles/org.openhab.automation.jythonscripting/ @openhab/add-ons-maintainers
 /bundles/org.openhab.binding.adorne/ @theiding
 /bundles/org.openhab.binding.airquality/ @kubawolanin
 /bundles/org.openhab.binding.airvisualnode/ @3cky
index ad1e3db6bc2e2d7e3e265a3b832b043bd7f776cc..94769faead16f260c45cd32f78c36212074bd43c 100644 (file)
       <artifactId>org.openhab.automation.groovyscripting</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.openhab.addons.bundles</groupId>
+      <artifactId>org.openhab.automation.jythonscripting</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.openhab.addons.bundles</groupId>
       <artifactId>org.openhab.binding.adorne</artifactId>
diff --git a/bundles/org.openhab.automation.jythonscripting/NOTICE b/bundles/org.openhab.automation.jythonscripting/NOTICE
new file mode 100644 (file)
index 0000000..38d625e
--- /dev/null
@@ -0,0 +1,13 @@
+This content is produced and maintained by the openHAB project.
+
+* Project home: https://www.openhab.org
+
+== Declared Project Licenses
+
+This program and the accompanying materials are made available under the terms
+of the Eclipse Public License 2.0 which is available at
+https://www.eclipse.org/legal/epl-2.0/.
+
+== Source Code
+
+https://github.com/openhab/openhab-addons
diff --git a/bundles/org.openhab.automation.jythonscripting/README.md b/bundles/org.openhab.automation.jythonscripting/README.md
new file mode 100644 (file)
index 0000000..ff6cab9
--- /dev/null
@@ -0,0 +1,5 @@
+# Jython Scripting
+
+This addon provides a [Jython](https://www.jython.org/) 2.7.2 for use with scripted automation and eliminates the need to download Jython and create `EXTRA_JAVA_OPTS` entries for `bootclasspath`, `python.home` and `python.path`.
+The `python.home` System property will be set to the path of the add-on.
+The `python.path` System property will be set to `$OPENHAB_CONF/automation/lib/python`, but any existing `python.path` will be appended to it.
diff --git a/bundles/org.openhab.automation.jythonscripting/pom.xml b/bundles/org.openhab.automation.jythonscripting/pom.xml
new file mode 100644 (file)
index 0000000..9b31f9d
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.openhab.addons.bundles</groupId>
+    <artifactId>org.openhab.addons.reactor.bundles</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>org.openhab.automation.jythonscripting</artifactId>
+
+  <name>openHAB Add-ons :: Automation :: Jython Scripting</name>
+
+  <properties>
+    <bnd.fixupmessages><![CDATA["Classes found in the wrong directory","The default package '.' is not permitted by the Import-Package syntax"; restrict:=error; is:=warning]]></bnd.fixupmessages>
+    <bnd.importpackage>*blockhound*;resolution:=optional,com.cloudius.util;resolution:=optional,com.github.luben.zstd;resolution:=optional,com.informix.jdbc;resolution:=optional,com.jcraft.jzlib;resolution:=optional,com.ning.compress.*;resolution:=optional,com.oracle.svm.core.annotate;resolution:=optional,com.sun.management;resolution:=optional,custom_proxymaker.tests;resolution:=optional,jnr.*;resolution;resolution:=optional,*jpountz*;resolution:=optional,junit.framework;resolution:=optional,lzma.sdk.*;resolution:=optional,oracle.*;resolution:=optional,org.antlr.stringtemplate;resolution:=optional,org.apache.tools.*;resolution:=optional,org.brotli.dec;resolution:=optional,org.checkerframework.*;resolution:=optional,org.conscrypt;resolution:=optional,org.eclipse.jetty.*;resolution:=optional,org.hamcrest;resolution:=optional,org.jboss.marshalling;resolution:=optional,org.junit.*;resolution:=optional,org.python.apache.xml.resolver.*;resolution:=optional,org.python.google.*;resolution:=optional,org.python.netty.internal.tcnative;resolution:=optional,org.python.objectweb.asm.tree.*;resolution:=optional,org.python.proxies;resolution:=optional,org.tukaani.xz;resolution:=optional,sun.*;resolution:=optional</bnd.importpackage>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.python</groupId>
+      <artifactId>jython-standalone</artifactId>
+      <version>2.7.2</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/bundles/org.openhab.automation.jythonscripting/src/main/feature/feature.xml b/bundles/org.openhab.automation.jythonscripting/src/main/feature/feature.xml
new file mode 100755 (executable)
index 0000000..9bec019
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<features name="org.openhab.automation.jythonscripting-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
+       <repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
+
+       <feature name="openhab-automation-jythonscripting" description="Jython Scripting" version="${project.version}">
+               <feature>openhab-runtime-base</feature>
+               <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.automation.jythonscripting/${project.version}</bundle>
+       </feature>
+</features>
diff --git a/bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/JythonScriptEngineFactory.java b/bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/JythonScriptEngineFactory.java
new file mode 100755 (executable)
index 0000000..a24608d
--- /dev/null
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.automation.jythonscripting;
+
+import java.io.File;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.script.ScriptEngine;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.OpenHAB;
+import org.openhab.core.automation.module.script.AbstractScriptEngineFactory;
+import org.openhab.core.automation.module.script.ScriptEngineFactory;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+
+/**
+ * This is an implementation of {@link ScriptEngineFactory} for Jython.
+ *
+ * @author Scott Rushworth - Initial contribution
+ * @author Wouter Born - Initial contribution
+ */
+@Component(service = ScriptEngineFactory.class)
+@NonNullByDefault
+public class JythonScriptEngineFactory extends AbstractScriptEngineFactory {
+
+    private static final String PYTHON_CACHEDIR = "python.cachedir";
+    private static final String PYTHON_HOME = "python.home";
+    private static final String PYTHON_PATH = "python.path";
+
+    private static final String DEFAULT_PYTHON_PATH = Paths
+            .get(OpenHAB.getConfigFolder(), "automation", "lib", "python").toString();
+
+    private static final String SCRIPT_TYPE = "py";
+    private static final javax.script.ScriptEngineManager ENGINE_MANAGER = new javax.script.ScriptEngineManager();
+
+    @Activate
+    public JythonScriptEngineFactory() {
+        logger.debug("Loading JythonScriptEngineFactory");
+
+        String pythonHome = JythonScriptEngineFactory.class.getProtectionDomain().getCodeSource().getLocation()
+                .toString().replace("file:", "");
+        System.setProperty(PYTHON_HOME, pythonHome);
+
+        String existingPythonPath = System.getProperty(PYTHON_PATH);
+        if (existingPythonPath == null || existingPythonPath.isEmpty()) {
+            System.setProperty(PYTHON_PATH, DEFAULT_PYTHON_PATH);
+        } else if (!existingPythonPath.contains(DEFAULT_PYTHON_PATH)) {
+            Set<String> newPythonPathList = new TreeSet<>(Arrays.asList(existingPythonPath.split(File.pathSeparator)));
+            newPythonPathList.add(DEFAULT_PYTHON_PATH);
+            System.setProperty(PYTHON_PATH, String.join(File.pathSeparator, newPythonPathList));
+        }
+
+        System.setProperty(PYTHON_CACHEDIR, Paths
+                .get(OpenHAB.getUserDataFolder(), "cache", JythonScriptEngineFactory.class.getPackageName(), "cachedir")
+                .toString());
+
+        logPythonPaths();
+    }
+
+    private void logPythonPaths() {
+        logger.trace("{}: {}, {}: {}, {}: {}", //
+                PYTHON_HOME, System.getProperty(PYTHON_HOME), //
+                PYTHON_PATH, System.getProperty(PYTHON_PATH), //
+                PYTHON_CACHEDIR, System.getProperty(PYTHON_CACHEDIR));
+    }
+
+    @Override
+    public List<String> getScriptTypes() {
+        List<String> scriptTypes = new ArrayList<>();
+
+        for (javax.script.ScriptEngineFactory factory : ENGINE_MANAGER.getEngineFactories()) {
+            List<String> extensions = factory.getExtensions();
+
+            if (extensions.contains(SCRIPT_TYPE)) {
+                scriptTypes.addAll(extensions);
+                scriptTypes.addAll(factory.getMimeTypes());
+            }
+        }
+        return scriptTypes;
+    }
+
+    @Override
+    public @Nullable ScriptEngine createScriptEngine(String scriptType) {
+        ScriptEngine scriptEngine = ENGINE_MANAGER.getEngineByExtension(scriptType);
+        if (scriptEngine == null) {
+            scriptEngine = ENGINE_MANAGER.getEngineByMimeType(scriptType);
+        }
+        if (scriptEngine == null) {
+            scriptEngine = ENGINE_MANAGER.getEngineByName(scriptType);
+        }
+        return scriptEngine;
+    }
+
+    @Deactivate
+    public void removePythonPath() {
+        logger.debug("Unloading JythonScriptEngineFactory");
+
+        String existingPythonPath = System.getProperty(PYTHON_PATH);
+        if (existingPythonPath != null && existingPythonPath.contains(DEFAULT_PYTHON_PATH)) {
+            Set<String> newPythonPathList = new TreeSet<>(Arrays.asList(existingPythonPath.split(File.pathSeparator)));
+            newPythonPathList.remove(DEFAULT_PYTHON_PATH);
+            System.setProperty(PYTHON_PATH, String.join(File.pathSeparator, newPythonPathList));
+        }
+
+        System.clearProperty(PYTHON_HOME);
+        System.clearProperty(PYTHON_CACHEDIR);
+
+        logPythonPaths();
+    }
+}
diff --git a/bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/package-info.java b/bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/package-info.java
new file mode 100644 (file)
index 0000000..80cb3d3
--- /dev/null
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+
+@org.osgi.annotation.bundle.Header(name = org.osgi.framework.Constants.DYNAMICIMPORT_PACKAGE, value = "*")
+package org.openhab.automation.jythonscripting;
+
+/**
+ * Additional information for the Jython Scripting package
+ *
+ * @author Wouter Born - Initial contribution
+ */
index 714dcb5a917874f5e5e8936caa46cbf178ad27f7..1d69ef8c099f1d149e7e02fb8e1df56fa8398700 100644 (file)
@@ -19,6 +19,7 @@
   <modules>
     <!-- automation -->
     <module>org.openhab.automation.groovyscripting</module>
+    <module>org.openhab.automation.jythonscripting</module>
     <!-- io -->
     <module>org.openhab.io.homekit</module>
     <module>org.openhab.io.hueemulation</module>
diff --git a/pom.xml b/pom.xml
index 48e68d21f9b555de2550e454e19f6e4440ece29b..6c394d6ed33f8bcd8608d9fd55c67e43ae3f4d3f 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -76,6 +76,7 @@
 
     <bnd.importpackage/>
     <bnd.exportpackage/>
+    <bnd.fixupmessages/>
     <bnd.includeresource>-${.}/NOTICE, -${.}/*.xsd</bnd.includeresource>
 
     <feature.directory>src/main/feature/feature.xml</feature.directory>
@@ -153,7 +154,8 @@ Import-Package: \\
   ${bnd.exportpackage}
 -sources: false
 -contract: *
--includeresource: ${bnd.includeresource}]]></bnd>
+-includeresource: ${bnd.includeresource}
+-fixupmessages: ${bnd.fixupmessages}]]></bnd>
             <!-- -dsannotations-options: norequirements -->
             <!-- Bundle-SymbolicName: ${project.groupId}.${project.artifactId} -->
           </configuration>