From e857f32a8afdd005d17ccf17a82d15928850e289 Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Sun, 17 Mar 2024 23:14:49 +0100 Subject: [PATCH] [jythonscripting] Refactor, improve and simplify (#16508) * moved implementation to 'internal' * refactored JythonScriptEngineFactory * implemented JythonScriptFileWatcher * fixed addon.xml & package-info.java * simplify stream list collector in JythonScriptEngineFactory * changed codeowner for jythonscripting * organized imports in JythonScriptEngineFactory Signed-off-by: Holger Hees --- CODEOWNERS | 2 +- .../JythonScriptEngineFactory.java | 103 ++++++++---------- .../{ => internal}/package-info.java | 3 +- .../watch/JythonScriptFileWatcher.java | 57 ++++++++++ .../src/main/resources/OH-INF/addon/addon.xml | 5 +- 5 files changed, 111 insertions(+), 59 deletions(-) rename bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/{ => internal}/JythonScriptEngineFactory.java (55%) rename bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/{ => internal}/package-info.java (85%) create mode 100644 bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/internal/watch/JythonScriptFileWatcher.java diff --git a/CODEOWNERS b/CODEOWNERS index 0a8e564cbb..a3a4786ac5 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -9,7 +9,7 @@ /bundles/org.openhab.automation.jrubyscripting/ @ccutrer @jimtng /bundles/org.openhab.automation.jsscripting/ @jpg0 @florian-h05 /bundles/org.openhab.automation.jsscriptingnashorn/ @wborn -/bundles/org.openhab.automation.jythonscripting/ @openhab/add-ons-maintainers +/bundles/org.openhab.automation.jythonscripting/ @HolgerHees /bundles/org.openhab.automation.pidcontroller/ @fwolter /bundles/org.openhab.automation.pwm/ @fwolter /bundles/org.openhab.binding.adorne/ @theiding 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/internal/JythonScriptEngineFactory.java similarity index 55% rename from bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/JythonScriptEngineFactory.java rename to bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/internal/JythonScriptEngineFactory.java index fc3ee61df3..5937f3c3a0 100644 --- 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/internal/JythonScriptEngineFactory.java @@ -10,15 +10,15 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.automation.jythonscripting; +package org.openhab.automation.jythonscripting.internal; 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 java.util.stream.Stream; import javax.script.ScriptEngine; @@ -36,93 +36,84 @@ import org.osgi.service.component.annotations.Deactivate; * * @author Scott Rushworth - Initial contribution * @author Wouter Born - Initial contribution + * @author Holger Hees - Further development */ @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_HOME_PATH = JythonScriptEngineFactory.class.getProtectionDomain().getCodeSource() + .getLocation().toString().replace("file:", ""); + private static final String PYTHON_PATH = "python.path"; + private static final String PYTHON_DEFAULT_PATH = Paths + .get(OpenHAB.getConfigFolder(), "automation", "jython", "lib").toString(); + + private static final String PYTHON_CACHEDIR = "python.cachedir"; + private static final String PYTHON_CACHEDIR_PATH = Paths + .get(OpenHAB.getUserDataFolder(), "cache", JythonScriptEngineFactory.class.getPackageName(), "cachedir") + .toString(); - private static final String DEFAULT_PYTHON_PATH = Paths - .get(OpenHAB.getConfigFolder(), "automation", "lib", "python").toString(); + private static final org.python.jsr223.PyScriptEngineFactory factory = new org.python.jsr223.PyScriptEngineFactory(); - private static final String SCRIPT_TYPE = "py"; - private static final javax.script.ScriptEngineManager ENGINE_MANAGER = new javax.script.ScriptEngineManager(); + private final List scriptTypes = (List) Stream.of(factory.getExtensions(), factory.getMimeTypes()) + .flatMap(List::stream) // + .toList(); @Activate public JythonScriptEngineFactory() { logger.debug("Loading JythonScriptEngineFactory"); - String pythonHome = JythonScriptEngineFactory.class.getProtectionDomain().getCodeSource().getLocation() - .toString().replace("file:", ""); - System.setProperty(PYTHON_HOME, pythonHome); + System.setProperty(PYTHON_HOME, PYTHON_HOME_PATH); + Set pythonPathList = new TreeSet<>(Arrays.asList(PYTHON_DEFAULT_PATH)); 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 newPythonPathList = new TreeSet<>(Arrays.asList(existingPythonPath.split(File.pathSeparator))); - newPythonPathList.add(DEFAULT_PYTHON_PATH); - System.setProperty(PYTHON_PATH, String.join(File.pathSeparator, newPythonPathList)); + if (existingPythonPath != null && !existingPythonPath.isEmpty()) { + pythonPathList.addAll(Arrays.asList(existingPythonPath.split(File.pathSeparator))); } + System.setProperty(PYTHON_PATH, String.join(File.pathSeparator, pythonPathList)); - System.setProperty(PYTHON_CACHEDIR, Paths - .get(OpenHAB.getUserDataFolder(), "cache", JythonScriptEngineFactory.class.getPackageName(), "cachedir") - .toString()); + System.setProperty(PYTHON_CACHEDIR, PYTHON_CACHEDIR_PATH); logPythonPaths(); } - private void logPythonPaths() { - logger.trace("{}: {}, {}: {}, {}: {}", // - PYTHON_HOME, System.getProperty(PYTHON_HOME), // - PYTHON_PATH, System.getProperty(PYTHON_PATH), // - PYTHON_CACHEDIR, System.getProperty(PYTHON_CACHEDIR)); + @Deactivate + public void cleanup() { + logger.debug("Unloading JythonScriptEngineFactory"); + + System.clearProperty(PYTHON_HOME); + + String existingPythonPath = System.getProperty(PYTHON_PATH); + if (existingPythonPath != null && !existingPythonPath.isEmpty()) { + Set newPythonPathList = new TreeSet<>(Arrays.asList(existingPythonPath.split(File.pathSeparator))); + newPythonPathList.remove(PYTHON_DEFAULT_PATH); + System.setProperty(PYTHON_PATH, String.join(File.pathSeparator, newPythonPathList)); + } + + System.clearProperty(PYTHON_CACHEDIR); + + logPythonPaths(); } @Override public List getScriptTypes() { - List scriptTypes = new ArrayList<>(); - - for (javax.script.ScriptEngineFactory factory : ENGINE_MANAGER.getEngineFactories()) { - List 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); + if (!scriptTypes.contains(scriptType)) { + return null; } - return scriptEngine; + return factory.getScriptEngine(); } - @Deactivate - public void removePythonPath() { - logger.debug("Unloading JythonScriptEngineFactory"); - - String existingPythonPath = System.getProperty(PYTHON_PATH); - if (existingPythonPath != null && existingPythonPath.contains(DEFAULT_PYTHON_PATH)) { - Set 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(); + private void logPythonPaths() { + logger.trace("{}: {}, {}: {}, {}: {}", // + PYTHON_HOME, System.getProperty(PYTHON_HOME), // + PYTHON_PATH, System.getProperty(PYTHON_PATH), // + PYTHON_CACHEDIR, System.getProperty(PYTHON_CACHEDIR)); } } 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/internal/package-info.java similarity index 85% rename from bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/package-info.java rename to bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/internal/package-info.java index 522363121f..66806c5fc1 100644 --- 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/internal/package-info.java @@ -11,10 +11,11 @@ * SPDX-License-Identifier: EPL-2.0 */ @org.osgi.annotation.bundle.Header(name = org.osgi.framework.Constants.DYNAMICIMPORT_PACKAGE, value = "*") -package org.openhab.automation.jythonscripting; +package org.openhab.automation.jythonscripting.internal; /** * Additional information for the Jython Scripting package * * @author Wouter Born - Initial contribution + * @author Holger Hees - Further development */ diff --git a/bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/internal/watch/JythonScriptFileWatcher.java b/bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/internal/watch/JythonScriptFileWatcher.java new file mode 100644 index 0000000000..3682dea1d5 --- /dev/null +++ b/bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/internal/watch/JythonScriptFileWatcher.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2010-2024 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.internal.watch; + +import java.io.File; +import java.nio.file.Path; +import java.util.Optional; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.automation.module.script.ScriptDependencyTracker; +import org.openhab.core.automation.module.script.ScriptEngineManager; +import org.openhab.core.automation.module.script.rulesupport.loader.AbstractScriptFileWatcher; +import org.openhab.core.automation.module.script.rulesupport.loader.ScriptFileWatcher; +import org.openhab.core.service.ReadyService; +import org.openhab.core.service.StartLevelService; +import org.openhab.core.service.WatchService; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * Monitors {@code /automation/jython} for Jython files, but not libraries + * + * @author Holger Hees - Initial contribution + */ +@Component(immediate = true, service = { ScriptFileWatcher.class, ScriptDependencyTracker.Listener.class }) +@NonNullByDefault +public class JythonScriptFileWatcher extends AbstractScriptFileWatcher { + private static final String FILE_DIRECTORY = "automation" + File.separator + "jython"; + + @Activate + public JythonScriptFileWatcher( + final @Reference(target = WatchService.CONFIG_WATCHER_FILTER) WatchService watchService, + final @Reference ScriptEngineManager manager, final @Reference ReadyService readyService, + final @Reference StartLevelService startLevelService) { + super(watchService, manager, readyService, startLevelService, FILE_DIRECTORY, true); + } + + @Override + protected Optional getScriptType(Path scriptFilePath) { + String scriptType = super.getScriptType(scriptFilePath).orElse(null); + if (!scriptFilePath.startsWith(getWatchPath().resolve("lib")) && ("py".equals(scriptType))) { + return Optional.of(scriptType); + } + return Optional.empty(); + } +} diff --git a/bundles/org.openhab.automation.jythonscripting/src/main/resources/OH-INF/addon/addon.xml b/bundles/org.openhab.automation.jythonscripting/src/main/resources/OH-INF/addon/addon.xml index 19bd7bbb56..d479fd0831 100644 --- a/bundles/org.openhab.automation.jythonscripting/src/main/resources/OH-INF/addon/addon.xml +++ b/bundles/org.openhab.automation.jythonscripting/src/main/resources/OH-INF/addon/addon.xml @@ -4,8 +4,11 @@ xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd"> automation - Jython Scripting (DEPRECATED) + Jython Scripting This adds a Jython script engine. none + org.openhab.automation.jythonscripting + + -- 2.47.3