[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 <holger.hees@gmail.com>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Holger Hees 2024-03-17 23:14:49 +01:00 committed by Ciprian Pascu
parent 2deacd47e1
commit b56e727ed8
5 changed files with 116 additions and 64 deletions

View File

@ -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

View File

@ -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 DEFAULT_PYTHON_PATH = Paths
.get(OpenHAB.getConfigFolder(), "automation", "lib", "python").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 SCRIPT_TYPE = "py";
private static final javax.script.ScriptEngineManager ENGINE_MANAGER = new javax.script.ScriptEngineManager();
private static final org.python.jsr223.PyScriptEngineFactory factory = new org.python.jsr223.PyScriptEngineFactory();
private final List<String> scriptTypes = (List<String>) 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<String> pythonPathList = new TreeSet<>(Arrays.asList(PYTHON_DEFAULT_PATH));
String existingPythonPath = System.getProperty(PYTHON_PATH);
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, PYTHON_CACHEDIR_PATH);
logPythonPaths();
}
@Deactivate
public void cleanup() {
logger.debug("Unloading JythonScriptEngineFactory");
System.clearProperty(PYTHON_HOME);
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)) {
if (existingPythonPath != null && !existingPythonPath.isEmpty()) {
Set<String> newPythonPathList = new TreeSet<>(Arrays.asList(existingPythonPath.split(File.pathSeparator)));
newPythonPathList.add(DEFAULT_PYTHON_PATH);
newPythonPathList.remove(PYTHON_DEFAULT_PATH);
System.setProperty(PYTHON_PATH, String.join(File.pathSeparator, newPythonPathList));
}
System.setProperty(PYTHON_CACHEDIR, Paths
.get(OpenHAB.getUserDataFolder(), "cache", JythonScriptEngineFactory.class.getPackageName(), "cachedir")
.toString());
System.clearProperty(PYTHON_CACHEDIR);
logPythonPaths();
}
@Override
public List<String> getScriptTypes() {
return scriptTypes;
}
@Override
public @Nullable ScriptEngine createScriptEngine(String scriptType) {
if (!scriptTypes.contains(scriptType)) {
return null;
}
return factory.getScriptEngine();
}
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();
}
}

View File

@ -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
*/

View File

@ -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 <openHAB-conf>/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<String> 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();
}
}

View File

@ -4,8 +4,11 @@
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
<type>automation</type>
<name>Jython Scripting (DEPRECATED)</name>
<name>Jython Scripting</name>
<description>This adds a Jython script engine.</description>
<connection>none</connection>
<service-id>org.openhab.automation.jythonscripting</service-id>
<config-description-ref uri="automation:jythonscripting"/>
</addon:addon>