c80f58fbeca1ce85646c3b7b43c2c46eafe05093
[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     final AxKey subjectKey;
43
44     private Context javascriptContext;
45     private Script script;
46
47     /**
48      * Initializes the Javascripe executor.
49      *
50      * @param subjectKey the key of the subject that is requesting Javascript execution
51      */
52     public JavascriptExecutor(final AxKey subjectKey) {
53         this.subjectKey = subjectKey;
54     }
55
56     /**
57      * Prepares the executor for processing and compiles the Javascript code.
58      *
59      * @param javascriptCode the Javascript code to execute
60      * @throws StateMachineException thrown when instantiation of the executor fails
61      */
62     public void init(final String javascriptCode) throws StateMachineException {
63         if (StringUtils.isEmpty(javascriptCode)) {
64             throw new StateMachineException("no logic specified for " + subjectKey.getId());
65         }
66
67         try {
68             // Create a Javascript context for this thread
69             javascriptContext = Context.enter();
70
71             // Set up the default values of the context
72             javascriptContext.setOptimizationLevel(DEFAULT_OPTIMIZATION_LEVEL);
73             javascriptContext.setLanguageVersion(Context.VERSION_1_8);
74
75             script = javascriptContext.compileString(javascriptCode, subjectKey.getId(), 1, null);
76         } catch (Exception e) {
77             Context.exit();
78             throw new StateMachineException(
79                     "logic failed to compile for " + subjectKey.getId() + WITH_MESSAGE + e.getMessage(), e);
80         }
81     }
82
83     /**
84      * Executes the the Javascript code.
85      *
86      * @param executionContext the execution context of the subject to be passed to the Javascript context
87      * @return true if the Javascript executed properly
88      * @throws StateMachineException thrown when Javascript execution fails
89      */
90     public boolean execute(final Object executionContext) throws StateMachineException {
91         Object returnObject = null;
92
93         try {
94             // Pass the subject context to the Javascript engine
95             Scriptable javascriptScope = javascriptContext.initStandardObjects();
96             javascriptScope.put("executor", javascriptScope, executionContext);
97
98             // Run the script
99             returnObject = script.exec(javascriptContext, javascriptScope);
100         } catch (final Exception e) {
101             throw new StateMachineException(
102                     "logic failed to run for " + subjectKey.getId() + WITH_MESSAGE + e.getMessage(), e);
103         }
104
105         if (!(returnObject instanceof Boolean)) {
106             throw new StateMachineException(
107                     "execute: logic for " + subjectKey.getId() + " returned a non-boolean value " + returnObject);
108         }
109
110         return (boolean) returnObject;
111     }
112
113     /**
114      * Cleans up the executor after processing.
115      *
116      * @throws StateMachineException thrown when cleanup of the executor fails
117      */
118     public void cleanUp() throws StateMachineException {
119         try {
120             Context.exit();
121         } catch (final Exception e) {
122             throw new StateMachineException("cleanUp: executor cleanup failed to close for " + subjectKey.getId()
123                     + WITH_MESSAGE + e.getMessage(), e);
124         }
125     }
126 }