From e982124b348151a5ab4e1a81a1e95b4b1ea1a96f Mon Sep 17 00:00:00 2001 From: Vasiliy Pankov Date: Sat, 24 Feb 2024 00:11:26 +0400 Subject: [PATCH] Feature - use environment variable to set ES6 support mode for Nashorn script evaluator (#88) Use environment variable CONDUCTOR_NASHORN_ES6_ENABLED=true to set ES6 support mode for Nashorn script evaluator. --- .../core/events/ScriptEvaluator.java | 31 ++++++++++---- .../conductor/core/events/TestScriptEval.java | 41 +++++++++++++++++++ .../sdk/workflow/def/tasks/Javascript.java | 20 +++++++-- 3 files changed, 82 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java b/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java index 1cd5e4a89..c77f3860d 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java +++ b/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java @@ -17,6 +17,8 @@ import javax.script.ScriptEngineManager; import javax.script.ScriptException; +import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory; + public class ScriptEvaluator { private static ScriptEngine engine; @@ -25,7 +27,7 @@ private ScriptEvaluator() {} /** * Evaluates the script with the help of input provided but converts the result to a boolean - * value. + * value. Set environment variable CONDUCTOR_NASHORN_ES6_ENABLED=true for Nashorn ES6 support. * * @param script Script to be evaluated. * @param input Input parameters. @@ -37,7 +39,8 @@ public static Boolean evalBool(String script, Object input) throws ScriptExcepti } /** - * Evaluates the script with the help of input provided. + * Evaluates the script with the help of input provided. Set environment variable + * CONDUCTOR_NASHORN_ES6_ENABLED=true for Nashorn ES6 support. * * @param script Script to be evaluated. * @param input Input parameters. @@ -45,16 +48,30 @@ public static Boolean evalBool(String script, Object input) throws ScriptExcepti * @return Generic object, the result of the evaluated expression. */ public static Object eval(String script, Object input) throws ScriptException { - if (engine == null) { - engine = new ScriptEngineManager().getEngineByName("Nashorn"); + initEngine(false); + Bindings bindings = engine.createBindings(); + bindings.put("$", input); + return engine.eval(script, bindings); + } + + // to mock in a test + public static String getEnv(String name) { + return System.getenv(name); + } + + public static void initEngine(boolean reInit) { + if (engine == null || reInit) { + if ("true".equalsIgnoreCase(getEnv("CONDUCTOR_NASHORN_ES6_ENABLED"))) { + NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + engine = factory.getScriptEngine("--language=es6"); + } else { + engine = new ScriptEngineManager().getEngineByName("Nashorn"); + } } if (engine == null) { throw new RuntimeException( "missing nashorn engine. Ensure you are running supported JVM"); } - Bindings bindings = engine.createBindings(); - bindings.put("$", input); - return engine.eval(script, bindings); } /** diff --git a/core/src/test/java/com/netflix/conductor/core/events/TestScriptEval.java b/core/src/test/java/com/netflix/conductor/core/events/TestScriptEval.java index 313c02bc3..3877a2093 100644 --- a/core/src/test/java/com/netflix/conductor/core/events/TestScriptEval.java +++ b/core/src/test/java/com/netflix/conductor/core/events/TestScriptEval.java @@ -16,6 +16,8 @@ import java.util.Map; import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -44,4 +46,43 @@ public void testScript() throws Exception { assertTrue(ScriptEvaluator.evalBool(script3, payload)); assertFalse(ScriptEvaluator.evalBool(script4, payload)); } + + @Test + public void testES6Setting() throws Exception { + Map payload = new HashMap<>(); + Map app = new HashMap<>(); + app.put("name", "conductor"); + app.put("version", 2.0); + app.put("license", "Apache 2.0"); + + payload.put("app", app); + payload.put("author", "Netflix"); + payload.put("oss", true); + + String script1 = + """ + (function(){\s + const variable = 1; // const support => es6\s + return $.app.name == 'conductor';})();"""; // true + + MockedStatic evaluator = Mockito.mockStatic(ScriptEvaluator.class); + evaluator + .when(() -> ScriptEvaluator.getEnv("CONDUCTOR_NASHORN_ES6_ENABLED")) + .thenReturn("true"); + evaluator + .when(() -> ScriptEvaluator.eval(Mockito.any(), Mockito.any())) + .thenCallRealMethod(); + evaluator + .when(() -> ScriptEvaluator.evalBool(Mockito.any(), Mockito.any())) + .thenCallRealMethod(); + evaluator.when(() -> ScriptEvaluator.initEngine(Mockito.anyBoolean())).thenCallRealMethod(); + evaluator.when(() -> ScriptEvaluator.toBoolean(Mockito.any())).thenCallRealMethod(); + ScriptEvaluator.initEngine(true); + assertTrue(ScriptEvaluator.evalBool(script1, payload)); + evaluator + .when(() -> ScriptEvaluator.getEnv("CONDUCTOR_NASHORN_ES6_ENABLED")) + .thenReturn("false"); + ScriptEvaluator.initEngine(true); + evaluator.close(); + } } diff --git a/java-sdk/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Javascript.java b/java-sdk/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Javascript.java index 7260a0586..d6d4af2ba 100644 --- a/java-sdk/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Javascript.java +++ b/java-sdk/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Javascript.java @@ -22,6 +22,7 @@ import javax.script.ScriptEngineManager; import javax.script.ScriptException; +import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +50,8 @@ public class Javascript extends Task { * Javascript tasks are executed on the Conductor server without having to write worker code * *

Use {@link Javascript#validate()} method to validate the javascript to ensure the script - * is valid. + * is valid. Set environment variable CONDUCTOR_NASHORN_ES6_ENABLED=true for Nashorn ES6 support + * during validation. * * @param taskReferenceName * @param script script to execute @@ -100,7 +102,13 @@ public String getExpression() { * @return */ public Javascript validate() { - ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("Nashorn"); + ScriptEngine scriptEngine; + if ("true".equalsIgnoreCase(System.getenv("CONDUCTOR_NASHORN_ES6_ENABLED"))) { + NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + scriptEngine = factory.getScriptEngine("--language=es6"); + } else { + scriptEngine = new ScriptEngineManager().getEngineByName("Nashorn"); + } if (scriptEngine == null) { LOGGER.error("missing " + ENGINE + " engine. Ensure you are running supported JVM"); return this; @@ -128,7 +136,13 @@ public Javascript validate() { */ public Object test(Map input) { - ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("Nashorn"); + ScriptEngine scriptEngine; + if ("true".equalsIgnoreCase(System.getenv("CONDUCTOR_NASHORN_ES6_ENABLED"))) { + NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + scriptEngine = factory.getScriptEngine("--language=es6"); + } else { + scriptEngine = new ScriptEngineManager().getEngineByName("Nashorn"); + } if (scriptEngine == null) { LOGGER.error("missing " + ENGINE + " engine. Ensure you are running supported JVM"); return this;