344f8c5ae43b4903b2bc20a34749ff87d4ab07b2
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2020 Nordix Foundation.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.apex.plugins.executor.javascript;
22
23 import org.apache.commons.lang3.StringUtils;
24 import org.mozilla.javascript.Context;
25 import org.mozilla.javascript.Script;
26 import org.mozilla.javascript.Scriptable;
27 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
28 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
29
30 /**
31  * The Class JavascriptExecutor is the executor for task logic written in Javascript.
32  *
33  * @author Liam Fallon (liam.fallon@ericsson.com)
34  */
35 public class JavascriptExecutor {
36     public static final int DEFAULT_OPTIMIZATION_LEVEL = 9;
37
38     // Recurring string constants
39     private static final String WITH_MESSAGE = " with message: ";
40
41     // The key of the subject that wants to execute Javascript code
42     private final AxKey subjectKey;
43
44     private final Script script;
45
46     /**
47      * Initializes the Javascript executor.
48      *
49      * @param subjectKey the key of the subject that is requesting Javascript execution
50      * @param javascriptCode the Javascript code to execute
51      */
52     public JavascriptExecutor(final AxKey subjectKey, String javascriptCode)  throws StateMachineException {
53         if (StringUtils.isBlank(javascriptCode)) {
54             throw new StateMachineException("no logic specified for " + subjectKey.getId());
55         }
56         this.subjectKey = subjectKey;
57         this.script = compile(subjectKey.getId(), javascriptCode);
58     }
59
60     /**
61      * Executes the Javascript code.
62      *
63      * @param executionContext the execution context of the subject to be passed to the Javascript context
64      * @return true if the Javascript executed properly
65      * @throws StateMachineException thrown when Javascript execution fails
66      */
67     public boolean execute(final Object executionContext) throws StateMachineException {
68         Object returnObject = null;
69
70         Context context = Context.enter();
71         try {
72             // Pass the subject context to the Javascript engine
73             Scriptable javascriptScope = context.initStandardObjects();
74             javascriptScope.put("executor", javascriptScope, executionContext);
75
76             // Run the script
77             returnObject = script.exec(context, javascriptScope);
78         } catch (final Exception e) {
79             throw new StateMachineException(
80                     "logic failed to run for " + subjectKey.getId() + WITH_MESSAGE + e.getMessage(), e);
81         } finally {
82             Context.exit();
83         }
84
85         if (!(returnObject instanceof Boolean)) {
86             throw new StateMachineException(
87                     "execute: logic for " + subjectKey.getId() + " returned a non-boolean value " + returnObject);
88         }
89
90         return (boolean) returnObject;
91     }
92
93     private Script compile(String id, String javascriptCode) throws StateMachineException {
94         Context context = Context.enter();
95         try {
96             // Set up the default values of the context
97             context.setOptimizationLevel(DEFAULT_OPTIMIZATION_LEVEL);
98             context.setLanguageVersion(Context.VERSION_1_8);
99             return context.compileString(javascriptCode, id, 1, null);
100         } catch (Exception e) {
101             throw new StateMachineException(
102                 "logic failed to compile for " + id + WITH_MESSAGE + e.getMessage(), e);
103         } finally {
104             Context.exit();
105         }
106     }
107 }