Merge pull request #787 from strangepleasures/JENA-1950
JENA-1950 Replace Nashorn with GraalVM-based JavaScript engine
diff --git a/jena-arq/pom.xml b/jena-arq/pom.xml
index 09f8322..61e7dc1 100644
--- a/jena-arq/pom.xml
+++ b/jena-arq/pom.xml
@@ -112,6 +112,20 @@
</dependency>
<dependency>
+ <groupId>org.graalvm.js</groupId>
+ <artifactId>js</artifactId>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.graalvm.js</groupId>
+ <artifactId>js-scriptengine</artifactId>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/function/js/FunctionJavaScript.java b/jena-arq/src/main/java/org/apache/jena/sparql/function/js/FunctionJavaScript.java
index 627cdff..63c0b96 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/function/js/FunctionJavaScript.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/js/FunctionJavaScript.java
@@ -55,8 +55,6 @@
private final EnvJavaScript envJS;
private final String functionName;
- private boolean initialized = false;
-
public FunctionJavaScript(String functionName, EnvJavaScript env) {
this.functionName = functionName;
this.envJS = env;
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/function/js/JSEngine.java b/jena-arq/src/main/java/org/apache/jena/sparql/function/js/JSEngine.java
index 9084beb..0eff562 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/function/js/JSEngine.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/js/JSEngine.java
@@ -36,13 +36,7 @@
/** Abstraction of a <em>per-thread</em> JavaScript execution system */
public class JSEngine {
- private ScriptEngine scriptEngine;
- private CompiledScript compiledScript;
-
private final Invocable invoc;
- private String functions;
-
- private String functionLibFile;
/** Create a {@code JSEngine} from a string. */
@@ -55,24 +49,29 @@
return new JSEngine(null, functionLibFile);
}
- /*package*/ JSEngine(String functions, String functionLibFile) {
- this.functions = functions;
- this.functionLibFile = functionLibFile;
+ /*package*/ JSEngine(String functions, String functionLibFile) {
invoc = build(functions, functionLibFile);
}
private static Invocable build(String functions, String functionLibFile) {
if ( functions == null && functionLibFile == null )
- throw new ARQException("Both script string and script filename are null");
+ throw new ARQException("Both script string and script filename are null");
ScriptEngineManager manager = new ScriptEngineManager();
- ScriptEngine scriptEngine = manager.getEngineByName("nashorn");
-
+ ScriptEngine scriptEngine = manager.getEngineByName("javascript");
+ if (scriptEngine == null) {
+ throw new ARQException("Could not load JavaScript script engine. " +
+ "Make sure that org.graalvm.js:js and org.graalvm.js:js-scriptengine are added to the class path");
+ }
+
+ if (scriptEngine.getFactory().getEngineName().equals("Graal.js")) {
+ scriptEngine.getContext().setAttribute("polyglot.js.nashorn-compat", true, ScriptContext.ENGINE_SCOPE);
+ }
+
Invocable invoc = (Invocable)scriptEngine;
if ( functionLibFile != null ) {
- try {
- Reader reader = Files.newBufferedReader(Paths.get(functionLibFile), StandardCharsets.UTF_8);
- Object x = scriptEngine.eval(reader);
+ try (Reader reader = Files.newBufferedReader(Paths.get(functionLibFile), StandardCharsets.UTF_8)) {
+ scriptEngine.eval(reader);
}
catch (NoSuchFileException | FileNotFoundException ex) {
throw new RiotNotFoundException("File: "+functionLibFile);
@@ -84,7 +83,7 @@
}
if ( functions != null ) {
try {
- Object x = scriptEngine.eval(functions);
+ scriptEngine.eval(functions);
}
catch (ScriptException e) {
throw new ExprBuildException("Failed to load Javascript", e);
@@ -94,7 +93,7 @@
// Try to call the init function - ignore NoSuchMethodException
try {
invoc.invokeFunction(ARQConstants.JavaScriptInitFunction);
- } catch (NoSuchMethodException ex) {}
+ } catch (NoSuchMethodException ignore) {}
catch (ScriptException ex) {
throw new ARQException("Failed to call JavaScript initialization function", ex);
}
@@ -104,6 +103,4 @@
public Object call(String functionName, Object[] args) throws NoSuchMethodException, ScriptException {
return invoc.invokeFunction(functionName, args);
}
-
-
}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/function/js/NV.java b/jena-arq/src/main/java/org/apache/jena/sparql/function/js/NV.java
index 50e982c..c73480d 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/function/js/NV.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/js/NV.java
@@ -31,7 +31,7 @@
/**
* General representation of an {@link NodeValue} for JavaScript. Conversion is to native
* types where possible, otherwise {@code NV}. {@code NV.toString} of a URI returns the
- * uri as a string so {@code NV} works naturally in Java/Nashorn.
+ * uri as a string so {@code NV} works naturally in Java/JavaScript.
*
* @see #fromNodeValue
* @see #toNodeValue
@@ -54,7 +54,7 @@
*/
private final static boolean narrowDoubles = true;
/**
- * Map an ARQ {@link NodeValue} to java/Nashorn representation of a JavaScript object.
+ * Map an ARQ {@link NodeValue} to java/Nashorn/GraalVM representation of a JavaScript object.
* Native JavaScript types supported are null, string, number and boolean.
* Otherwise a {@link NV} is returned.
*/
@@ -76,7 +76,7 @@
return new NV(nv);
}
/**
- * Map a java/Nashorn representation of a JavaScript object to an ARQ
+ * Map a java/Nashorn/GraalVM representation of a JavaScript object to an ARQ
* {@link NodeValue}. Identified types are null, string, number and boolean and also
* {@code NV} returned by the JavaScript code.
*/
@@ -103,7 +103,7 @@
throw new ExprEvalException("Can't convert '"+r+"' to a NodeValue. r is of class "+r.getClass().getName());
}
- // Convert the numeric values that Nashorn can return.
+ // Convert the numeric values that JavaScript can return.
static NodeValue number2value(Number r) {
if ( r instanceof Integer )
return NodeValue.makeInteger((Integer)r);
diff --git a/pom.xml b/pom.xml
index e862fad..2f28792 100644
--- a/pom.xml
+++ b/pom.xml
@@ -102,6 +102,8 @@
<ver.awaitility>3.1.0</ver.awaitility>
<ver.micrometer>1.2.1</ver.micrometer>
+ <ver.graalvm>20.2.0</ver.graalvm>
+
<jdk.version>1.8</jdk.version>
<targetJdk>${jdk.version}</targetJdk>
@@ -559,6 +561,18 @@
</dependency>
<dependency>
+ <groupId>org.graalvm.js</groupId>
+ <artifactId>js</artifactId>
+ <version>${ver.graalvm}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.graalvm.js</groupId>
+ <artifactId>js-scriptengine</artifactId>
+ <version>${ver.graalvm}</version>
+ </dependency>
+
+ <dependency>
<groupId>org.xenei</groupId>
<artifactId>junit-contracts</artifactId>
<version>${ver.contract.tests}</version>
@@ -602,6 +616,7 @@
<artifactId>micrometer-registry-prometheus</artifactId>
<version>${ver.micrometer}</version>
</dependency>
+
</dependencies>
</dependencyManagement>