diff options
author | liamfallon <liam.fallon@est.tech> | 2020-03-05 10:50:48 +0000 |
---|---|---|
committer | liamfallon <liam.fallon@est.tech> | 2020-03-09 18:30:13 +0000 |
commit | 6bda5d7e4e80d1aefb4f19203361b7199448e70f (patch) | |
tree | b28a68625cec91c57f0383d185f73fdf165ab558 /plugins/plugins-executor/plugins-executor-javascript/src/main | |
parent | f876b34ec297495df20394c248b899d610e1bcce (diff) |
Use Rhino javascript executor in apex-pdp
Integation unit tests resultd in StackOverflowException errors in the
Graal Javascript interpreter. Following extensive testing and
trouobleshooting, it proved very difficult to fix these issues in Graal
as the stck overflow errors were occurring in native class instantiation
methods being invoked by Grall on the JVM.
The alternative Rhino Javascript engine is developed by mozilla, and was
incorporated into the Java 6 JVM and evolved into Nashorn in the Java 8
JVM. Oracle dropped Nashorn in Java 11. However, in parallel, Rhino
development has continued.
This review brings in the Rhino javascript engine into apex-pdp as the
replacement for Nashorn and instead of Graal. Graal seems to be pretty
unstable as yet so we may bring it in in future releases but for now
Rhino is a more stable and reliable alternative.
Issue-ID: POLICY-2106
Change-Id: I0edeff3b0bee404b38e3ebe22001a6e3375a44dc
Signed-off-by: liamfallon <liam.fallon@est.tech>
Diffstat (limited to 'plugins/plugins-executor/plugins-executor-javascript/src/main')
4 files changed, 86 insertions, 44 deletions
diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptExecutor.java b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptExecutor.java index 93f6216fc..c80f58fbe 100644 --- a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptExecutor.java +++ b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptExecutor.java @@ -20,9 +20,10 @@ package org.onap.policy.apex.plugins.executor.javascript; -import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.HostAccess; -import org.graalvm.polyglot.Value; +import org.apache.commons.lang3.StringUtils; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Script; +import org.mozilla.javascript.Scriptable; import org.onap.policy.apex.core.engine.executor.exception.StateMachineException; import org.onap.policy.apex.model.basicmodel.concepts.AxKey; @@ -32,35 +33,50 @@ import org.onap.policy.apex.model.basicmodel.concepts.AxKey; * @author Liam Fallon (liam.fallon@ericsson.com) */ public class JavascriptExecutor { + public static final int DEFAULT_OPTIMIZATION_LEVEL = 9; + + // Recurring string constants + private static final String WITH_MESSAGE = " with message: "; + // The key of the subject that wants to execute Javascript code final AxKey subjectKey; - // The Javascript context - private final Context jsContext; + private Context javascriptContext; + private Script script; /** - * Prepares the executor for processing. + * Initializes the Javascripe executor. * * @param subjectKey the key of the subject that is requesting Javascript execution - * @throws StateMachineException thrown when instantiation of the executor fails */ - public JavascriptExecutor(final AxKey subjectKey) throws StateMachineException { + public JavascriptExecutor(final AxKey subjectKey) { this.subjectKey = subjectKey; + } - // @formatter:off - jsContext = - Context.newBuilder("js") - .allowHostClassLookup(s -> true) - .allowHostAccess(HostAccess.ALL) - .build(); - // @formatter:on + /** + * Prepares the executor for processing and compiles the Javascript code. + * + * @param javascriptCode the Javascript code to execute + * @throws StateMachineException thrown when instantiation of the executor fails + */ + public void init(final String javascriptCode) throws StateMachineException { + if (StringUtils.isEmpty(javascriptCode)) { + throw new StateMachineException("no logic specified for " + subjectKey.getId()); + } try { - jsContext.getBindings("js"); + // Create a Javascript context for this thread + javascriptContext = Context.enter(); + + // Set up the default values of the context + javascriptContext.setOptimizationLevel(DEFAULT_OPTIMIZATION_LEVEL); + javascriptContext.setLanguageVersion(Context.VERSION_1_8); + + script = javascriptContext.compileString(javascriptCode, subjectKey.getId(), 1, null); } catch (Exception e) { - jsContext.close(); + Context.exit(); throw new StateMachineException( - "prepare: javascript engine failed to initialize properly for \"" + subjectKey.getId() + "\"", e); + "logic failed to compile for " + subjectKey.getId() + WITH_MESSAGE + e.getMessage(), e); } } @@ -68,28 +84,30 @@ public class JavascriptExecutor { * Executes the the Javascript code. * * @param executionContext the execution context of the subject to be passed to the Javascript context - * @param javascriptCode the Javascript code to execute * @return true if the Javascript executed properly * @throws StateMachineException thrown when Javascript execution fails */ - public boolean execute(final Object executionContext, final String javascriptCode) throws StateMachineException { + public boolean execute(final Object executionContext) throws StateMachineException { + Object returnObject = null; + try { - // Set up the Javascript engine context - jsContext.getBindings("js").putMember("executor", executionContext); - jsContext.eval("js", javascriptCode); + // Pass the subject context to the Javascript engine + Scriptable javascriptScope = javascriptContext.initStandardObjects(); + javascriptScope.put("executor", javascriptScope, executionContext); + // Run the script + returnObject = script.exec(javascriptContext, javascriptScope); } catch (final Exception e) { - throw new StateMachineException("execute: logic failed to run for \"" + subjectKey.getId() + "\"", e); + throw new StateMachineException( + "logic failed to run for " + subjectKey.getId() + WITH_MESSAGE + e.getMessage(), e); } - Value returnValue = jsContext.getBindings("js").getMember("returnValue"); - - if (returnValue == null || returnValue.isNull()) { + if (!(returnObject instanceof Boolean)) { throw new StateMachineException( - "execute: logic failed to set a return value for \"" + subjectKey.getId() + "\""); + "execute: logic for " + subjectKey.getId() + " returned a non-boolean value " + returnObject); } - return returnValue.asBoolean(); + return (boolean) returnObject; } /** @@ -99,10 +117,10 @@ public class JavascriptExecutor { */ public void cleanUp() throws StateMachineException { try { - jsContext.close(); + Context.exit(); } catch (final Exception e) { - throw new StateMachineException( - "cleanUp: executor cleanup failed to close for \"" + subjectKey.getId() + "\"", e); + throw new StateMachineException("cleanUp: executor cleanup failed to close for " + subjectKey.getId() + + WITH_MESSAGE + e.getMessage(), e); } } } diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutor.java b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutor.java index 18a6ef58a..27e649fd3 100644 --- a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutor.java +++ b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutor.java @@ -52,7 +52,12 @@ public class JavascriptStateFinalizerExecutor extends StateFinalizerExecutor { // Call generic prepare logic super.prepare(); + // Create the executor javascriptExecutor = new JavascriptExecutor(getSubject().getKey()); + + // Initialize and cleanup the executor to check the Javascript code + javascriptExecutor.init(getSubject().getLogic()); + javascriptExecutor.cleanUp(); } /** @@ -71,8 +76,13 @@ public class JavascriptStateFinalizerExecutor extends StateFinalizerExecutor { // Do execution pre work executePre(executionId, executionProperties, incomingFields); - // Execute the Javascript and do post processing - executePost(javascriptExecutor.execute(getExecutionContext(), getSubject().getLogic())); + // Execute the Javascript executor + javascriptExecutor.init(getSubject().getLogic()); + boolean result = javascriptExecutor.execute(getExecutionContext()); + javascriptExecutor.cleanUp(); + + // Execute the Javascript + executePost(result); return getOutgoing(); } @@ -86,7 +96,5 @@ public class JavascriptStateFinalizerExecutor extends StateFinalizerExecutor { public void cleanUp() throws StateMachineException { LOGGER.debug("cleanUp:" + getSubject().getKey().getId() + "," + getSubject().getLogicFlavour() + "," + getSubject().getLogic()); - - javascriptExecutor.cleanUp(); } } diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutor.java b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutor.java index 29fae193e..bec5670c5 100644 --- a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutor.java +++ b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutor.java @@ -52,7 +52,12 @@ public class JavascriptTaskExecutor extends TaskExecutor { // Call generic prepare logic super.prepare(); + // Create the executor javascriptExecutor = new JavascriptExecutor(getSubject().getKey()); + + // Initialize and cleanup the executor to check the Javascript code + javascriptExecutor.init(getSubject().getTaskLogic().getLogic()); + javascriptExecutor.cleanUp(); } /** @@ -68,11 +73,17 @@ public class JavascriptTaskExecutor extends TaskExecutor { @Override public Map<String, Object> execute(final long executionId, final Properties executionProperties, final Map<String, Object> incomingFields) throws StateMachineException, ContextException { + // Do execution pre work executePre(executionId, executionProperties, incomingFields); - // Execute the Javascript and do post processing - executePost(javascriptExecutor.execute(getExecutionContext(), getSubject().getTaskLogic().getLogic())); + // Execute the Javascript executor + javascriptExecutor.init(getSubject().getTaskLogic().getLogic()); + boolean result = javascriptExecutor.execute(getExecutionContext()); + javascriptExecutor.cleanUp(); + + // Execute the Javascript + executePost(result); return getOutgoing(); } @@ -86,7 +97,5 @@ public class JavascriptTaskExecutor extends TaskExecutor { public void cleanUp() throws StateMachineException { LOGGER.debug("cleanUp:" + getSubject().getKey().getId() + "," + getSubject().getTaskLogic().getLogicFlavour() + "," + getSubject().getTaskLogic().getLogic()); - - javascriptExecutor.cleanUp(); } } diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutor.java b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutor.java index 41585fbd0..c32b70991 100644 --- a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutor.java +++ b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutor.java @@ -53,7 +53,11 @@ public class JavascriptTaskSelectExecutor extends TaskSelectExecutor { // Call generic prepare logic super.prepare(); + // Create the executor javascriptExecutor = new JavascriptExecutor(getSubject().getKey()); + + // Initialize and cleanup the executor to check the Javascript code + javascriptExecutor.init(getSubject().getTaskSelectionLogic().getLogic()); } /** @@ -72,8 +76,13 @@ public class JavascriptTaskSelectExecutor extends TaskSelectExecutor { // Do execution pre work executePre(executionId, executionProperties, incomingEvent); - // Execute the Javascript and do post processing - executePost(javascriptExecutor.execute(getExecutionContext(), getSubject().getTaskSelectionLogic().getLogic())); + // Execute the Javascript executor + javascriptExecutor.init(getSubject().getTaskSelectionLogic().getLogic()); + boolean result = javascriptExecutor.execute(getExecutionContext()); + javascriptExecutor.cleanUp(); + + // Execute the Javascript + executePost(result); return getOutgoing(); } @@ -88,7 +97,5 @@ public class JavascriptTaskSelectExecutor extends TaskSelectExecutor { LOGGER.debug("cleanUp:" + getSubject().getKey().getId() + "," + getSubject().getTaskSelectionLogic().getLogicFlavour() + "," + getSubject().getTaskSelectionLogic().getLogic()); - - javascriptExecutor.cleanUp(); } } |