GH-3664: Re-enable JavaScript support via GraalVM (#3911)

* GH-3664: Re-enable JavaScript support via GraalVM

Fixes https://github.com/spring-projects/spring-integration/issues/3664

The JavaScript JSR223 engine has been removed from Java.

Migrate JavaScript support into GraalVM Polyglot API:
* Implement `PolyglotScriptExecutor` which can also support other GraalVM languages
* Change the `ScriptExecutorFactory` to use a `PolyglotScriptExecutor` when it encounters JavaScript
* Re-enable tests for JavaScript
* Add GraalVM Polyglot support into docs

* * Reinstate `@EnabledIfSystemProperty` for GraalVM JS system property
This commit is contained in:
Artem Bilan
2022-10-11 14:38:46 -04:00
committed by GitHub
parent 1dd8b6bed5
commit 6641b1f545
8 changed files with 118 additions and 9 deletions

View File

@@ -0,0 +1,77 @@
/*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.scripting;
import java.util.Map;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
import org.springframework.lang.Nullable;
import org.springframework.scripting.ScriptSource;
import org.springframework.util.Assert;
/**
* GraalVM Polyglot {@link ScriptExecutor} implementation.
*
* @author Artem Bilan
*
* @since 6.0
*/
public class PolyglotScriptExecutor implements ScriptExecutor {
private final String language;
private Context.Builder contextBuilder;
/**
* Construct an executor based on the provided language id.
* @param language the supported by GraalVM language id.
*/
public PolyglotScriptExecutor(String language) {
this(language, Context.newBuilder().allowAllAccess(true));
}
/**
* Construct an executor based on the provided language id.
* @param language the supported by GraalVM language id.
*/
public PolyglotScriptExecutor(String language, Context.Builder contextBuilder) {
Assert.hasText(language, "'language' must not be empty");
Assert.notNull(contextBuilder, "'contextBuilder' must not be null");
this.contextBuilder = contextBuilder;
this.language = language;
try (Context context = this.contextBuilder.build()) {
context.initialize(language);
}
}
@Override
public Object executeScript(ScriptSource scriptSource, @Nullable Map<String, Object> variables) {
try (Context context = this.contextBuilder.build()) {
if (variables != null) {
Value bindings = context.getBindings(this.language);
variables.forEach(bindings::putMember);
}
return context.eval(this.language, scriptSource.getScriptAsString()).as(Object.class);
}
catch (Exception ex) {
throw new ScriptingException(ex.getMessage(), ex);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package org.springframework.integration.scripting.jsr223;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import org.springframework.integration.scripting.PolyglotScriptExecutor;
import org.springframework.integration.scripting.ScriptExecutor;
import org.springframework.util.Assert;
@@ -42,6 +43,9 @@ public final class ScriptExecutorFactory {
else if (language.equalsIgnoreCase("kotlin")) {
return new KotlinScriptExecutor();
}
else if (language.equalsIgnoreCase("js") || language.equalsIgnoreCase("javascript")) {
return new PolyglotScriptExecutor("js");
}
return new DefaultScriptExecutor(language);
}
@@ -58,6 +62,9 @@ public final class ScriptExecutorFactory {
if (extension.equals("kts")) {
return "kotlin";
}
else if (extension.equals("js")) {
return "js";
}
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByExtension(extension);
Assert.state(engine != null, () -> "No suitable scripting engine found for extension '" + extension + "'");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2021 the original author or authors.
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.