[jsscripting] Implement javax.script.Compilable (#16970)

* [jsscripting] Restructure & Comment POM
* [jsscripting] Use OPENHAB_TRANSFORMATION_SCRIPT constant from core

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
This commit is contained in:
Florian Hotze 2024-07-09 20:08:30 +02:00 committed by Leo Siepel
parent ef3ffff2bc
commit e69fd47ef2
6 changed files with 74 additions and 31 deletions

View File

@ -27,6 +27,7 @@
<build> <build>
<plugins> <plugins>
<!-- exclude META-INF/services/com.oracle.truffle.api.TruffleLanguage$Provider when unpacking dependencies -->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId> <artifactId>maven-dependency-plugin</artifactId>
@ -42,6 +43,7 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<!-- bundle the openhab-js library -->
<plugin> <plugin>
<groupId>com.github.eirslett</groupId> <groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId> <artifactId>frontend-maven-plugin</artifactId>
@ -112,6 +114,7 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<!-- run SAT -->
<plugin> <plugin>
<groupId>org.openhab.tools.sat</groupId> <groupId>org.openhab.tools.sat</groupId>
<artifactId>sat-plugin</artifactId> <artifactId>sat-plugin</artifactId>
@ -123,32 +126,33 @@
</build> </build>
<dependencies> <dependencies>
<dependency>
<groupId>org.graalvm.truffle</groupId>
<artifactId>truffle-api</artifactId>
<version>${graal.version}</version>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js-scriptengine</artifactId>
<version>${graal.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.graalvm.sdk</groupId> <groupId>org.graalvm.sdk</groupId>
<artifactId>graal-sdk</artifactId> <artifactId>graal-sdk</artifactId>
<version>${graal.version}</version> <version>${graal.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.graalvm.truffle</groupId>
<artifactId>truffle-api</artifactId>
<version>${graal.version}</version>
</dependency>
<!-- Graal JavaScript ScriptEngine JSR 223 support -->
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js-scriptengine</artifactId>
<version>${graal.version}</version>
</dependency>
<!-- Graal TRegex engine (internally used by Graal JavaScript engine) -->
<dependency> <dependency>
<groupId>org.graalvm.regex</groupId> <groupId>org.graalvm.regex</groupId>
<artifactId>regex</artifactId> <artifactId>regex</artifactId>
<version>${graal.version}</version> <version>${graal.version}</version>
</dependency> </dependency>
<dependency> <!-- this must come AFTER the regex lib --> <!-- Graal JavaScript engine (depends on Graal TRegex engine, must be added after it) -->
<dependency>
<groupId>org.graalvm.js</groupId> <groupId>org.graalvm.js</groupId>
<artifactId>js</artifactId> <artifactId>js</artifactId>
<version>${graal.version}</version> <version>${graal.version}</version>
</dependency> </dependency>
<!-- GraalJS changelog says that com.ibm.icu/icu4j is not required for GraalJS >= 22.0.0 as it moved to org.graalvm.truffle;
but GraalJS >= 22.2.0 requires it, so we'll need to add it when we upgrade -->
</dependencies> </dependencies>
</project> </project>

View File

@ -12,16 +12,19 @@
*/ */
package org.openhab.automation.jsscripting.internal; package org.openhab.automation.jsscripting.internal;
import static org.openhab.core.automation.module.script.ScriptTransformationService.OPENHAB_TRANSFORMATION_SCRIPT;
import java.util.Arrays; import java.util.Arrays;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.script.Compilable;
import javax.script.Invocable; import javax.script.Invocable;
import javax.script.ScriptContext; import javax.script.ScriptContext;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.PolyglotException;
import org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable; import org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -31,10 +34,9 @@ import org.slf4j.LoggerFactory;
* @author Jonathan Gilbert - Initial contribution * @author Jonathan Gilbert - Initial contribution
* @author Florian Hotze - Improve logger name, Fix memory leak caused by exception logging * @author Florian Hotze - Improve logger name, Fix memory leak caused by exception logging
*/ */
class DebuggingGraalScriptEngine<T extends ScriptEngine & Invocable & AutoCloseable> class DebuggingGraalScriptEngine<T extends ScriptEngine & Invocable & AutoCloseable & Compilable>
extends InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable<T> { extends InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable<T> {
private static final String SCRIPT_TRANSFORMATION_ENGINE_IDENTIFIER = "openhab-transformation-script-";
private static final int STACK_TRACE_LENGTH = 5; private static final int STACK_TRACE_LENGTH = 5;
private @Nullable Logger logger; private @Nullable Logger logger;
@ -91,9 +93,8 @@ class DebuggingGraalScriptEngine<T extends ScriptEngine & Invocable & AutoClosea
} else if (ruleUID != null) { } else if (ruleUID != null) {
identifier = ruleUID.toString(); identifier = ruleUID.toString();
} else if (ohEngineIdentifier != null) { } else if (ohEngineIdentifier != null) {
if (ohEngineIdentifier.toString().startsWith(SCRIPT_TRANSFORMATION_ENGINE_IDENTIFIER)) { if (ohEngineIdentifier.toString().startsWith(OPENHAB_TRANSFORMATION_SCRIPT)) {
identifier = ohEngineIdentifier.toString().replaceAll(SCRIPT_TRANSFORMATION_ENGINE_IDENTIFIER, identifier = ohEngineIdentifier.toString().replaceAll(OPENHAB_TRANSFORMATION_SCRIPT, "transformation.");
"transformation.");
} }
} }

View File

@ -50,7 +50,7 @@ import org.openhab.automation.jsscripting.internal.fs.DelegatingFileSystem;
import org.openhab.automation.jsscripting.internal.fs.PrefixedSeekableByteChannel; import org.openhab.automation.jsscripting.internal.fs.PrefixedSeekableByteChannel;
import org.openhab.automation.jsscripting.internal.fs.ReadOnlySeekableByteArrayChannel; import org.openhab.automation.jsscripting.internal.fs.ReadOnlySeekableByteArrayChannel;
import org.openhab.automation.jsscripting.internal.fs.watch.JSDependencyTracker; import org.openhab.automation.jsscripting.internal.fs.watch.JSDependencyTracker;
import org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable; import org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable;
import org.openhab.core.automation.module.script.ScriptExtensionAccessor; import org.openhab.core.automation.module.script.ScriptExtensionAccessor;
import org.openhab.core.items.Item; import org.openhab.core.items.Item;
import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.QuantityType;
@ -69,7 +69,7 @@ import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine;
* {@link Lock} for multi-thread synchronization; globals and openhab-js injection code caching * {@link Lock} for multi-thread synchronization; globals and openhab-js injection code caching
*/ */
public class OpenhabGraalJSScriptEngine public class OpenhabGraalJSScriptEngine
extends InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable<GraalJSScriptEngine> { extends InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable<GraalJSScriptEngine> {
private static final Logger LOGGER = LoggerFactory.getLogger(OpenhabGraalJSScriptEngine.class); private static final Logger LOGGER = LoggerFactory.getLogger(OpenhabGraalJSScriptEngine.class);
private static final Source GLOBAL_SOURCE; private static final Source GLOBAL_SOURCE;

View File

@ -15,6 +15,8 @@ package org.openhab.automation.jsscripting.internal.scriptengine;
import java.io.Reader; import java.io.Reader;
import javax.script.Bindings; import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable; import javax.script.Invocable;
import javax.script.ScriptContext; import javax.script.ScriptContext;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
@ -29,11 +31,11 @@ import org.eclipse.jdt.annotation.NonNull;
* *
* @author Jonathan Gilbert - Initial contribution * @author Jonathan Gilbert - Initial contribution
*/ */
public abstract class DelegatingScriptEngineWithInvocableAndAutocloseable<T extends ScriptEngine & Invocable & AutoCloseable> public abstract class DelegatingScriptEngineWithInvocableAndCompilableAndAutocloseable<T extends ScriptEngine & Invocable & Compilable & AutoCloseable>
implements ScriptEngine, Invocable, AutoCloseable { implements ScriptEngine, Invocable, Compilable, AutoCloseable {
protected @NonNull T delegate; protected @NonNull T delegate;
public DelegatingScriptEngineWithInvocableAndAutocloseable(@NonNull T delegate) { public DelegatingScriptEngineWithInvocableAndCompilableAndAutocloseable(@NonNull T delegate) {
this.delegate = delegate; this.delegate = delegate;
} }
@ -128,6 +130,16 @@ public abstract class DelegatingScriptEngineWithInvocableAndAutocloseable<T exte
return delegate.getInterface(o, aClass); return delegate.getInterface(o, aClass);
} }
@Override
public CompiledScript compile(String s) throws ScriptException {
return delegate.compile(s);
}
@Override
public CompiledScript compile(Reader reader) throws ScriptException {
return delegate.compile(reader);
}
@Override @Override
public void close() throws Exception { public void close() throws Exception {
delegate.close(); delegate.close();

View File

@ -16,22 +16,24 @@ import java.io.Reader;
import java.lang.reflect.UndeclaredThrowableException; import java.lang.reflect.UndeclaredThrowableException;
import javax.script.Bindings; import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable; import javax.script.Invocable;
import javax.script.ScriptContext; import javax.script.ScriptContext;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
import javax.script.ScriptException; import javax.script.ScriptException;
/** /**
* Delegate allowing AOP-style interception of calls, either before Invocation, or upon a {@link ScriptException}. * Delegate allowing AOP-style interception of calls, either before Invocation, or upon a {@link ScriptException} being
* being thrown. * thrown.
* *
* @param <T> The delegate class * @param <T> The delegate class
* @author Jonathan Gilbert - Initial contribution * @author Jonathan Gilbert - Initial contribution
*/ */
public abstract class InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable<T extends ScriptEngine & Invocable & AutoCloseable> public abstract class InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable<T extends ScriptEngine & Invocable & Compilable & AutoCloseable>
extends DelegatingScriptEngineWithInvocableAndAutocloseable<T> { extends DelegatingScriptEngineWithInvocableAndCompilableAndAutocloseable<T> {
public InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable(T delegate) { public InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable(T delegate) {
super(delegate); super(delegate);
} }
@ -155,4 +157,28 @@ public abstract class InvocationInterceptingScriptEngineWithInvocableAndAutoClos
throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions
} }
} }
@Override
public CompiledScript compile(String s) throws ScriptException {
try {
beforeInvocation();
return (CompiledScript) afterInvocation(super.compile(s));
} catch (ScriptException se) {
throw (ScriptException) afterThrowsInvocation(se);
} catch (Exception e) {
throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions
}
}
@Override
public CompiledScript compile(Reader reader) throws ScriptException {
try {
beforeInvocation();
return (CompiledScript) afterInvocation(super.compile(reader));
} catch (ScriptException se) {
throw (ScriptException) afterThrowsInvocation(se);
} catch (Exception e) {
throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions
}
}
} }

View File

@ -1,3 +1,3 @@
# Please check here how to add suppressions https://maven.apache.org/plugins/maven-pmd-plugin/examples/violation-exclusions.html # Please check here how to add suppressions https://maven.apache.org/plugins/maven-pmd-plugin/examples/violation-exclusions.html
org.openhab.automation.jsscripting.internal.OpenhabGraalJSScriptEngine=UnusedPrivateField org.openhab.automation.jsscripting.internal.OpenhabGraalJSScriptEngine=UnusedPrivateField
org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable=AvoidThrowingNullPointerException,AvoidCatchingNPE org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable=AvoidThrowingNullPointerException,AvoidCatchingNPE