From caae6b0f6e9c9bb3a3f98dbbc3afa0dd97549880 Mon Sep 17 00:00:00 2001 From: Jonathan Gilbert Date: Sun, 12 Dec 2021 22:06:37 +0000 Subject: [PATCH] GraalJS now uses automation/js (#11719) * GraalJS now uses automation/js Signed-off-by: Jonathan Gilbert --- .../internal/GraalJSScriptEngineFactory.java | 19 ++++-- .../internal/OpenhabGraalJSScriptEngine.java | 11 ++-- .../fs/watch/JSDependencyTracker.java | 60 +++++++++++++++++ .../fs/watch/JSScriptFileWatcher.java | 65 +++++++++++++++++++ 4 files changed, 143 insertions(+), 12 deletions(-) create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSDependencyTracker.java create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSScriptFileWatcher.java diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java index 14e9f783e8348..d6b98efeb7382 100644 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java @@ -22,8 +22,6 @@ import org.openhab.core.automation.module.script.ScriptEngineFactory; import org.osgi.service.component.annotations.Component; -import com.oracle.truffle.js.scriptengine.GraalJSEngineFactory; - /** * An implementation of {@link ScriptEngineFactory} with customizations for GraalJS ScriptEngines. * @@ -32,13 +30,24 @@ @Component(service = ScriptEngineFactory.class) public final class GraalJSScriptEngineFactory implements ScriptEngineFactory { + public static final String MIME_TYPE = "application/javascript;version=ECMAScript-2021"; + @Override public List getScriptTypes() { List scriptTypes = new ArrayList<>(); - GraalJSEngineFactory graalJSEngineFactory = new GraalJSEngineFactory(); - scriptTypes.addAll(graalJSEngineFactory.getMimeTypes()); - scriptTypes.addAll(graalJSEngineFactory.getExtensions()); + /* + * Whilst we run in parallel with Nashorn, we use a custom mime-type to avoid + * disrupting Nashorn scripts. When Nashorn is removed, we take over the standard + * JS runtime. + */ + + // GraalJSEngineFactory graalJSEngineFactory = new GraalJSEngineFactory(); + // + // scriptTypes.addAll(graalJSEngineFactory.getMimeTypes()); + // scriptTypes.addAll(graalJSEngineFactory.getExtensions()); + + scriptTypes.add(MIME_TYPE); return Collections.unmodifiableList(scriptTypes); } diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java index 9f29b0d99d2c7..6621d5d1a1578 100644 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java @@ -10,12 +10,10 @@ * * SPDX-License-Identifier: EPL-2.0 */ - package org.openhab.automation.jsscripting.internal; import static org.openhab.core.automation.module.script.ScriptEngineFactory.*; -import java.io.File; import java.io.IOException; import java.nio.channels.SeekableByteChannel; import java.nio.file.FileSystems; @@ -33,8 +31,8 @@ import org.graalvm.polyglot.Engine; import org.openhab.automation.jsscripting.internal.fs.DelegatingFileSystem; import org.openhab.automation.jsscripting.internal.fs.PrefixedSeekableByteChannel; +import org.openhab.automation.jsscripting.internal.fs.watch.JSDependencyTracker; import org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocable; -import org.openhab.core.OpenHAB; import org.openhab.core.automation.module.script.ScriptExtensionAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,8 +49,6 @@ public class OpenhabGraalJSScriptEngine extends InvocationInterceptingScriptEngi private static final Logger LOGGER = LoggerFactory.getLogger(OpenhabGraalJSScriptEngine.class); private static final String REQUIRE_WRAPPER_NAME = "__wraprequire__"; - private static final String MODULE_DIR = String.join(File.separator, OpenHAB.getConfigFolder(), "automation", "lib", - "javascript", "personal"); // these fields start as null because they are populated on first use private @NonNullByDefault({}) String engineIdentifier; @@ -70,8 +66,9 @@ public OpenhabGraalJSScriptEngine() { Engine.newBuilder().allowExperimentalOptions(true).option("engine.WarnInterpreterOnly", "false") .build(), Context.newBuilder("js").allowExperimentalOptions(true).allowAllAccess(true) - .option("js.commonjs-require-cwd", MODULE_DIR).option("js.nashorn-compat", "true") // to ease - // migration + .option("js.commonjs-require-cwd", JSDependencyTracker.LIB_PATH) + .option("js.nashorn-compat", "true") // to ease + // migration .option("js.ecmascript-version", "2021") // nashorn compat will enforce es5 compatibility, we // want ecma2021 .option("js.commonjs-require", "true") // enable CommonJS module support diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSDependencyTracker.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSDependencyTracker.java new file mode 100644 index 0000000000000..aed75a0930696 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSDependencyTracker.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2010-2021 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.jsscripting.internal.fs.watch; + +import java.io.File; + +import org.openhab.core.OpenHAB; +import org.openhab.core.automation.module.script.rulesupport.loader.DependencyTracker; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Tracks JS module dependencies + * + * @author Jonathan Gilbert - Initial contribution + */ +@Component(immediate = true, service = JSDependencyTracker.class) +public class JSDependencyTracker extends DependencyTracker { + + private final Logger logger = LoggerFactory.getLogger(JSDependencyTracker.class); + + public static final String LIB_PATH = String.join(File.separator, OpenHAB.getConfigFolder(), "automation", "js", + "node_modules"); + + public JSDependencyTracker() { + super(LIB_PATH); + } + + @Activate + public void activate() { + File directory = new File(LIB_PATH); + if (!directory.exists()) { + if (!directory.mkdirs()) { + logger.warn("Failed to create watched directory: {}", LIB_PATH); + } + } else if (directory.isFile()) { + logger.warn("Trying to watch directory {}, however it is a file", LIB_PATH); + } + + super.activate(); + } + + @Deactivate + public void deactivate() { + super.deactivate(); + } +} diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSScriptFileWatcher.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSScriptFileWatcher.java new file mode 100644 index 0000000000000..39dca7f3da661 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSScriptFileWatcher.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2010-2021 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.jsscripting.internal.fs.watch; + +import java.io.File; +import java.util.Optional; + +import org.openhab.automation.jsscripting.internal.GraalJSScriptEngineFactory; +import org.openhab.core.automation.module.script.ScriptEngineManager; +import org.openhab.core.automation.module.script.rulesupport.loader.ScriptFileReference; +import org.openhab.core.automation.module.script.rulesupport.loader.ScriptFileWatcher; +import org.openhab.core.service.ReadyService; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; + +/** + * Monitors /automation/js for Javascript files + * + * @author Jonathan Gilbert - Initial contribution + */ +@Component(immediate = true) +public class JSScriptFileWatcher extends ScriptFileWatcher { + private static final String FILE_DIRECTORY = "automation" + File.separator + "js"; + + @Activate + public JSScriptFileWatcher(final @Reference ScriptEngineManager manager, final @Reference ReadyService readyService, + final @Reference JSDependencyTracker jsDependencyTracker) { + super(manager, jsDependencyTracker, readyService, FILE_DIRECTORY); + } + + @Activate + @Override + public void activate() { + super.activate(); + } + + @Deactivate + @Override + public void deactivate() { + super.deactivate(); + } + + @Override + protected boolean createAndLoad(ScriptFileReference ref) { + return super.createAndLoad(new ScriptFileReference(ref.getScriptFileURL()) { + @Override + public Optional getScriptType() { + assert super.getScriptType().get().equalsIgnoreCase("js"); + return Optional.of(GraalJSScriptEngineFactory.MIME_TYPE); + } + }); + } +}