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:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 + "'");
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user