Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[jythonscripting] Refactor, improve and simplify #16508

Merged
merged 4 commits into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -36,93 +36,84 @@
*
* @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<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()) {
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));
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<String> 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<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);
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<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();
private void logPythonPaths() {
logger.trace("{}: {}, {}: {}, {}: {}", //
PYTHON_HOME, System.getProperty(PYTHON_HOME), //
PYTHON_PATH, System.getProperty(PYTHON_PATH), //
PYTHON_CACHEDIR, System.getProperty(PYTHON_CACHEDIR));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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>