Commit f73fbc5ee94b64874f5b329c85a28b686204797e
1 parent
04432ee7
JavaScript Sandbox Service improvements.
Showing
22 changed files
with
302 additions
and
136 deletions
@@ -44,7 +44,7 @@ import org.thingsboard.server.dao.relation.RelationService; | @@ -44,7 +44,7 @@ import org.thingsboard.server.dao.relation.RelationService; | ||
44 | import org.thingsboard.server.dao.rule.RuleChainService; | 44 | import org.thingsboard.server.dao.rule.RuleChainService; |
45 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 45 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
46 | import org.thingsboard.server.dao.user.UserService; | 46 | import org.thingsboard.server.dao.user.UserService; |
47 | -import org.thingsboard.server.service.script.JsScriptEngine; | 47 | +import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; |
48 | import scala.concurrent.duration.Duration; | 48 | import scala.concurrent.duration.Duration; |
49 | 49 | ||
50 | import java.util.Collections; | 50 | import java.util.Collections; |
@@ -151,8 +151,8 @@ class DefaultTbContext implements TbContext { | @@ -151,8 +151,8 @@ class DefaultTbContext implements TbContext { | ||
151 | } | 151 | } |
152 | 152 | ||
153 | @Override | 153 | @Override |
154 | - public ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames) { | ||
155 | - return new JsScriptEngine(mainCtx.getJsSandbox(), script, functionName, argNames); | 154 | + public ScriptEngine createJsScriptEngine(String script, String... argNames) { |
155 | + return new RuleNodeJsScriptEngine(mainCtx.getJsSandbox(), script, argNames); | ||
156 | } | 156 | } |
157 | 157 | ||
158 | @Override | 158 | @Override |
@@ -50,9 +50,8 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; | @@ -50,9 +50,8 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; | ||
50 | import org.thingsboard.server.common.msg.TbMsg; | 50 | import org.thingsboard.server.common.msg.TbMsg; |
51 | import org.thingsboard.server.common.msg.TbMsgMetaData; | 51 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
52 | import org.thingsboard.server.dao.event.EventService; | 52 | import org.thingsboard.server.dao.event.EventService; |
53 | -import org.thingsboard.server.service.script.JsExecutorService; | ||
54 | import org.thingsboard.server.service.script.JsSandboxService; | 53 | import org.thingsboard.server.service.script.JsSandboxService; |
55 | -import org.thingsboard.server.service.script.JsScriptEngine; | 54 | +import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; |
56 | 55 | ||
57 | import java.util.List; | 56 | import java.util.List; |
58 | import java.util.Map; | 57 | import java.util.Map; |
@@ -266,7 +265,6 @@ public class RuleChainController extends BaseController { | @@ -266,7 +265,6 @@ public class RuleChainController extends BaseController { | ||
266 | try { | 265 | try { |
267 | String script = inputParams.get("script").asText(); | 266 | String script = inputParams.get("script").asText(); |
268 | String scriptType = inputParams.get("scriptType").asText(); | 267 | String scriptType = inputParams.get("scriptType").asText(); |
269 | - String functionName = inputParams.get("functionName").asText(); | ||
270 | JsonNode argNamesJson = inputParams.get("argNames"); | 268 | JsonNode argNamesJson = inputParams.get("argNames"); |
271 | String[] argNames = objectMapper.treeToValue(argNamesJson, String[].class); | 269 | String[] argNames = objectMapper.treeToValue(argNamesJson, String[].class); |
272 | 270 | ||
@@ -278,7 +276,7 @@ public class RuleChainController extends BaseController { | @@ -278,7 +276,7 @@ public class RuleChainController extends BaseController { | ||
278 | String errorText = ""; | 276 | String errorText = ""; |
279 | ScriptEngine engine = null; | 277 | ScriptEngine engine = null; |
280 | try { | 278 | try { |
281 | - engine = new JsScriptEngine(jsSandboxService, script, functionName, argNames); | 279 | + engine = new RuleNodeJsScriptEngine(jsSandboxService, script, argNames); |
282 | TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data, null, null, 0L); | 280 | TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data, null, null, 0L); |
283 | switch (scriptType) { | 281 | switch (scriptType) { |
284 | case "update": | 282 | case "update": |
application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsSandboxService.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package org.thingsboard.server.service.script; | ||
18 | + | ||
19 | +import com.google.common.util.concurrent.Futures; | ||
20 | +import com.google.common.util.concurrent.ListenableFuture; | ||
21 | +import delight.nashornsandbox.NashornSandbox; | ||
22 | +import delight.nashornsandbox.NashornSandboxes; | ||
23 | +import lombok.extern.slf4j.Slf4j; | ||
24 | + | ||
25 | +import javax.annotation.PostConstruct; | ||
26 | +import javax.annotation.PreDestroy; | ||
27 | +import javax.script.ScriptException; | ||
28 | +import java.util.Map; | ||
29 | +import java.util.UUID; | ||
30 | +import java.util.concurrent.ConcurrentHashMap; | ||
31 | +import java.util.concurrent.ExecutorService; | ||
32 | +import java.util.concurrent.Executors; | ||
33 | +import java.util.concurrent.atomic.AtomicInteger; | ||
34 | + | ||
35 | +@Slf4j | ||
36 | +public abstract class AbstractNashornJsSandboxService implements JsSandboxService { | ||
37 | + | ||
38 | + private NashornSandbox sandbox = NashornSandboxes.create(); | ||
39 | + private ExecutorService monitorExecutorService; | ||
40 | + | ||
41 | + private Map<UUID, String> functionsMap = new ConcurrentHashMap<>(); | ||
42 | + | ||
43 | + private Map<UUID,AtomicInteger> blackListedFunctions = new ConcurrentHashMap<>(); | ||
44 | + | ||
45 | + @PostConstruct | ||
46 | + public void init() { | ||
47 | + monitorExecutorService = Executors.newFixedThreadPool(getMonitorThreadPoolSize()); | ||
48 | + sandbox.setExecutor(monitorExecutorService); | ||
49 | + sandbox.setMaxCPUTime(getMaxCpuTime()); | ||
50 | + sandbox.allowNoBraces(false); | ||
51 | + sandbox.setMaxPreparedStatements(30); | ||
52 | + } | ||
53 | + | ||
54 | + @PreDestroy | ||
55 | + public void stop() { | ||
56 | + if (monitorExecutorService != null) { | ||
57 | + monitorExecutorService.shutdownNow(); | ||
58 | + } | ||
59 | + } | ||
60 | + | ||
61 | + protected abstract int getMonitorThreadPoolSize(); | ||
62 | + | ||
63 | + protected abstract long getMaxCpuTime(); | ||
64 | + | ||
65 | + protected abstract int getMaxErrors(); | ||
66 | + | ||
67 | + @Override | ||
68 | + public ListenableFuture<UUID> eval(JsScriptType scriptType, String scriptBody, String... argNames) { | ||
69 | + UUID scriptId = UUID.randomUUID(); | ||
70 | + String functionName = "invokeInternal_" + scriptId.toString().replace('-','_'); | ||
71 | + String jsScript = generateJsScript(scriptType, functionName, scriptBody, argNames); | ||
72 | + try { | ||
73 | + sandbox.eval(jsScript); | ||
74 | + functionsMap.put(scriptId, functionName); | ||
75 | + } catch (Exception e) { | ||
76 | + log.warn("Failed to compile JS script: {}", e.getMessage(), e); | ||
77 | + return Futures.immediateFailedFuture(e); | ||
78 | + } | ||
79 | + return Futures.immediateFuture(scriptId); | ||
80 | + } | ||
81 | + | ||
82 | + @Override | ||
83 | + public ListenableFuture<Object> invokeFunction(UUID scriptId, Object... args) { | ||
84 | + String functionName = functionsMap.get(scriptId); | ||
85 | + if (functionName == null) { | ||
86 | + return Futures.immediateFailedFuture(new RuntimeException("No compiled script found for scriptId: [" + scriptId + "]!")); | ||
87 | + } | ||
88 | + if (!isBlackListed(scriptId)) { | ||
89 | + try { | ||
90 | + return Futures.immediateFuture(sandbox.getSandboxedInvocable().invokeFunction(functionName, args)); | ||
91 | + } catch (Exception e) { | ||
92 | + blackListedFunctions.computeIfAbsent(scriptId, key -> new AtomicInteger(0)).incrementAndGet(); | ||
93 | + return Futures.immediateFailedFuture(e); | ||
94 | + } | ||
95 | + } else { | ||
96 | + return Futures.immediateFailedFuture( | ||
97 | + new RuntimeException("Script is blacklisted due to maximum error count " + getMaxErrors() + "!")); | ||
98 | + } | ||
99 | + } | ||
100 | + | ||
101 | + @Override | ||
102 | + public ListenableFuture<Void> release(UUID scriptId) { | ||
103 | + String functionName = functionsMap.get(scriptId); | ||
104 | + if (functionName != null) { | ||
105 | + try { | ||
106 | + sandbox.eval(functionName + " = undefined;"); | ||
107 | + functionsMap.remove(scriptId); | ||
108 | + blackListedFunctions.remove(scriptId); | ||
109 | + } catch (ScriptException e) { | ||
110 | + return Futures.immediateFailedFuture(e); | ||
111 | + } | ||
112 | + } | ||
113 | + return Futures.immediateFuture(null); | ||
114 | + } | ||
115 | + | ||
116 | + private boolean isBlackListed(UUID scriptId) { | ||
117 | + if (blackListedFunctions.containsKey(scriptId)) { | ||
118 | + AtomicInteger errorCount = blackListedFunctions.get(scriptId); | ||
119 | + return errorCount.get() >= getMaxErrors(); | ||
120 | + } else { | ||
121 | + return false; | ||
122 | + } | ||
123 | + } | ||
124 | + | ||
125 | + private String generateJsScript(JsScriptType scriptType, String functionName, String scriptBody, String... argNames) { | ||
126 | + switch (scriptType) { | ||
127 | + case RULE_NODE_SCRIPT: | ||
128 | + return RuleNodeScriptFactory.generateRuleNodeScript(functionName, scriptBody, argNames); | ||
129 | + default: | ||
130 | + throw new RuntimeException("No script factory implemented for scriptType: " + scriptType); | ||
131 | + } | ||
132 | + } | ||
133 | +} |
@@ -16,12 +16,16 @@ | @@ -16,12 +16,16 @@ | ||
16 | 16 | ||
17 | package org.thingsboard.server.service.script; | 17 | package org.thingsboard.server.service.script; |
18 | 18 | ||
19 | -import javax.script.ScriptException; | 19 | +import com.google.common.util.concurrent.ListenableFuture; |
20 | + | ||
21 | +import java.util.UUID; | ||
20 | 22 | ||
21 | public interface JsSandboxService { | 23 | public interface JsSandboxService { |
22 | 24 | ||
23 | - Object eval(String js) throws ScriptException; | 25 | + ListenableFuture<UUID> eval(JsScriptType scriptType, String scriptBody, String... argNames); |
26 | + | ||
27 | + ListenableFuture<Object> invokeFunction(UUID scriptId, Object... args); | ||
24 | 28 | ||
25 | - Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException; | 29 | + ListenableFuture<Void> release(UUID scriptId); |
26 | 30 | ||
27 | } | 31 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package org.thingsboard.server.service.script; | ||
18 | + | ||
19 | +public enum JsScriptType { | ||
20 | + RULE_NODE_SCRIPT | ||
21 | +} |
@@ -16,21 +16,13 @@ | @@ -16,21 +16,13 @@ | ||
16 | 16 | ||
17 | package org.thingsboard.server.service.script; | 17 | package org.thingsboard.server.service.script; |
18 | 18 | ||
19 | -import delight.nashornsandbox.NashornSandbox; | ||
20 | -import delight.nashornsandbox.NashornSandboxes; | ||
21 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
22 | import org.springframework.beans.factory.annotation.Value; | 20 | import org.springframework.beans.factory.annotation.Value; |
23 | import org.springframework.stereotype.Service; | 21 | import org.springframework.stereotype.Service; |
24 | 22 | ||
25 | -import javax.annotation.PostConstruct; | ||
26 | -import javax.annotation.PreDestroy; | ||
27 | -import javax.script.ScriptException; | ||
28 | -import java.util.concurrent.ExecutorService; | ||
29 | -import java.util.concurrent.Executors; | ||
30 | - | ||
31 | @Slf4j | 23 | @Slf4j |
32 | @Service | 24 | @Service |
33 | -public class NashornJsSandboxService implements JsSandboxService { | 25 | +public class NashornJsSandboxService extends AbstractNashornJsSandboxService { |
34 | 26 | ||
35 | @Value("${actors.rule.js_sandbox.monitor_thread_pool_size}") | 27 | @Value("${actors.rule.js_sandbox.monitor_thread_pool_size}") |
36 | private int monitorThreadPoolSize; | 28 | private int monitorThreadPoolSize; |
@@ -38,33 +30,21 @@ public class NashornJsSandboxService implements JsSandboxService { | @@ -38,33 +30,21 @@ public class NashornJsSandboxService implements JsSandboxService { | ||
38 | @Value("${actors.rule.js_sandbox.max_cpu_time}") | 30 | @Value("${actors.rule.js_sandbox.max_cpu_time}") |
39 | private long maxCpuTime; | 31 | private long maxCpuTime; |
40 | 32 | ||
41 | - private NashornSandbox sandbox = NashornSandboxes.create(); | ||
42 | - private ExecutorService monitorExecutorService; | ||
43 | - | ||
44 | - @PostConstruct | ||
45 | - public void init() { | ||
46 | - monitorExecutorService = Executors.newFixedThreadPool(monitorThreadPoolSize); | ||
47 | - sandbox.setExecutor(monitorExecutorService); | ||
48 | - sandbox.setMaxCPUTime(maxCpuTime); | ||
49 | - sandbox.allowNoBraces(false); | ||
50 | - sandbox.setMaxPreparedStatements(30); | ||
51 | - } | 33 | + @Value("${actors.rule.js_sandbox.max_errors}") |
34 | + private int maxErrors; | ||
52 | 35 | ||
53 | - @PreDestroy | ||
54 | - public void stop() { | ||
55 | - if (monitorExecutorService != null) { | ||
56 | - monitorExecutorService.shutdownNow(); | ||
57 | - } | 36 | + @Override |
37 | + protected int getMonitorThreadPoolSize() { | ||
38 | + return monitorThreadPoolSize; | ||
58 | } | 39 | } |
59 | 40 | ||
60 | @Override | 41 | @Override |
61 | - public Object eval(String js) throws ScriptException { | ||
62 | - return sandbox.eval(js); | 42 | + protected long getMaxCpuTime() { |
43 | + return maxCpuTime; | ||
63 | } | 44 | } |
64 | 45 | ||
65 | @Override | 46 | @Override |
66 | - public Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException { | ||
67 | - return sandbox.getSandboxedInvocable().invokeFunction(name, args); | 47 | + protected int getMaxErrors() { |
48 | + return maxErrors; | ||
68 | } | 49 | } |
69 | - | ||
70 | } | 50 | } |
application/src/main/java/org/thingsboard/server/service/script/RuleNodeJsScriptEngine.java
renamed from
application/src/main/java/org/thingsboard/server/service/script/JsScriptEngine.java
@@ -28,56 +28,23 @@ import javax.script.ScriptException; | @@ -28,56 +28,23 @@ import javax.script.ScriptException; | ||
28 | import java.util.Collections; | 28 | import java.util.Collections; |
29 | import java.util.Map; | 29 | import java.util.Map; |
30 | import java.util.Set; | 30 | import java.util.Set; |
31 | +import java.util.UUID; | ||
32 | +import java.util.concurrent.ExecutionException; | ||
31 | 33 | ||
32 | 34 | ||
33 | @Slf4j | 35 | @Slf4j |
34 | -public class JsScriptEngine implements org.thingsboard.rule.engine.api.ScriptEngine { | ||
35 | - | ||
36 | - public static final String MSG = "msg"; | ||
37 | - public static final String METADATA = "metadata"; | ||
38 | - public static final String MSG_TYPE = "msgType"; | ||
39 | - | ||
40 | - private static final String JS_WRAPPER_PREFIX_TEMPLATE = "function %s(msgStr, metadataStr, msgType) { " + | ||
41 | - " var msg = JSON.parse(msgStr); " + | ||
42 | - " var metadata = JSON.parse(metadataStr); " + | ||
43 | - " return JSON.stringify(%s(msg, metadata, msgType));" + | ||
44 | - " function %s(%s, %s, %s) {"; | ||
45 | - private static final String JS_WRAPPER_SUFFIX = "}" + | ||
46 | - "\n}"; | 36 | +public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.ScriptEngine { |
47 | 37 | ||
48 | private static final ObjectMapper mapper = new ObjectMapper(); | 38 | private static final ObjectMapper mapper = new ObjectMapper(); |
49 | -// private static NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); | ||
50 | -// private ScriptEngine engine = factory.getScriptEngine(new String[]{"--no-java"}); | ||
51 | private final JsSandboxService sandboxService; | 39 | private final JsSandboxService sandboxService; |
52 | 40 | ||
53 | - private final String invokeFunctionName; | 41 | + private final UUID scriptId; |
54 | 42 | ||
55 | - public JsScriptEngine(JsSandboxService sandboxService, String script, String functionName, String... argNames) { | 43 | + public RuleNodeJsScriptEngine(JsSandboxService sandboxService, String script, String... argNames) { |
56 | this.sandboxService = sandboxService; | 44 | this.sandboxService = sandboxService; |
57 | - this.invokeFunctionName = "invokeInternal" + this.hashCode(); | ||
58 | - String msgArg; | ||
59 | - String metadataArg; | ||
60 | - String msgTypeArg; | ||
61 | - if (argNames != null && argNames.length == 3) { | ||
62 | - msgArg = argNames[0]; | ||
63 | - metadataArg = argNames[1]; | ||
64 | - msgTypeArg = argNames[2]; | ||
65 | - } else { | ||
66 | - msgArg = MSG; | ||
67 | - metadataArg = METADATA; | ||
68 | - msgTypeArg = MSG_TYPE; | ||
69 | - } | ||
70 | - String jsWrapperPrefix = String.format(JS_WRAPPER_PREFIX_TEMPLATE, this.invokeFunctionName, | ||
71 | - functionName, functionName, msgArg, metadataArg, msgTypeArg); | ||
72 | - compileScript(jsWrapperPrefix + script + JS_WRAPPER_SUFFIX); | ||
73 | - } | ||
74 | - | ||
75 | - private void compileScript(String script) { | ||
76 | try { | 45 | try { |
77 | - //engine.eval(script); | ||
78 | - sandboxService.eval(script); | ||
79 | - } catch (ScriptException e) { | ||
80 | - log.warn("Failed to compile JS script: {}", e.getMessage(), e); | 46 | + this.scriptId = this.sandboxService.eval(JsScriptType.RULE_NODE_SCRIPT, script, argNames).get(); |
47 | + } catch (Exception e) { | ||
81 | throw new IllegalArgumentException("Can't compile script: " + e.getMessage()); | 48 | throw new IllegalArgumentException("Can't compile script: " + e.getMessage()); |
82 | } | 49 | } |
83 | } | 50 | } |
@@ -103,17 +70,17 @@ public class JsScriptEngine implements org.thingsboard.rule.engine.api.ScriptEng | @@ -103,17 +70,17 @@ public class JsScriptEngine implements org.thingsboard.rule.engine.api.ScriptEng | ||
103 | String data = null; | 70 | String data = null; |
104 | Map<String, String> metadata = null; | 71 | Map<String, String> metadata = null; |
105 | String messageType = null; | 72 | String messageType = null; |
106 | - if (msgData.has(MSG)) { | ||
107 | - JsonNode msgPayload = msgData.get(MSG); | 73 | + if (msgData.has(RuleNodeScriptFactory.MSG)) { |
74 | + JsonNode msgPayload = msgData.get(RuleNodeScriptFactory.MSG); | ||
108 | data = mapper.writeValueAsString(msgPayload); | 75 | data = mapper.writeValueAsString(msgPayload); |
109 | } | 76 | } |
110 | - if (msgData.has(METADATA)) { | ||
111 | - JsonNode msgMetadata = msgData.get(METADATA); | 77 | + if (msgData.has(RuleNodeScriptFactory.METADATA)) { |
78 | + JsonNode msgMetadata = msgData.get(RuleNodeScriptFactory.METADATA); | ||
112 | metadata = mapper.convertValue(msgMetadata, new TypeReference<Map<String, String>>() { | 79 | metadata = mapper.convertValue(msgMetadata, new TypeReference<Map<String, String>>() { |
113 | }); | 80 | }); |
114 | } | 81 | } |
115 | - if (msgData.has(MSG_TYPE)) { | ||
116 | - messageType = msgData.get(MSG_TYPE).asText(); | 82 | + if (msgData.has(RuleNodeScriptFactory.MSG_TYPE)) { |
83 | + messageType = msgData.get(RuleNodeScriptFactory.MSG_TYPE).asText(); | ||
117 | } | 84 | } |
118 | String newData = data != null ? data : msg.getData(); | 85 | String newData = data != null ? data : msg.getData(); |
119 | TbMsgMetaData newMetadata = metadata != null ? new TbMsgMetaData(metadata) : msg.getMetaData().copy(); | 86 | TbMsgMetaData newMetadata = metadata != null ? new TbMsgMetaData(metadata) : msg.getMetaData().copy(); |
@@ -195,18 +162,20 @@ public class JsScriptEngine implements org.thingsboard.rule.engine.api.ScriptEng | @@ -195,18 +162,20 @@ public class JsScriptEngine implements org.thingsboard.rule.engine.api.ScriptEng | ||
195 | private JsonNode executeScript(TbMsg msg) throws ScriptException { | 162 | private JsonNode executeScript(TbMsg msg) throws ScriptException { |
196 | try { | 163 | try { |
197 | String[] inArgs = prepareArgs(msg); | 164 | String[] inArgs = prepareArgs(msg); |
198 | - //String eval = ((Invocable)engine).invokeFunction(this.invokeFunctionName, inArgs[0], inArgs[1], inArgs[2]).toString(); | ||
199 | - String eval = sandboxService.invokeFunction(this.invokeFunctionName, inArgs[0], inArgs[1], inArgs[2]).toString(); | 165 | + String eval = sandboxService.invokeFunction(this.scriptId, inArgs[0], inArgs[1], inArgs[2]).get().toString(); |
200 | return mapper.readTree(eval); | 166 | return mapper.readTree(eval); |
201 | - } catch (ScriptException | IllegalArgumentException th) { | ||
202 | - throw th; | ||
203 | - } catch (Throwable th) { | ||
204 | - th.printStackTrace(); | ||
205 | - throw new RuntimeException("Failed to execute js script", th); | 167 | + } catch (ExecutionException e) { |
168 | + if (e.getCause() instanceof ScriptException) { | ||
169 | + throw (ScriptException)e.getCause(); | ||
170 | + } else { | ||
171 | + throw new ScriptException("Failed to execute js script: " + e.getMessage()); | ||
172 | + } | ||
173 | + } catch (Exception e) { | ||
174 | + throw new ScriptException("Failed to execute js script: " + e.getMessage()); | ||
206 | } | 175 | } |
207 | } | 176 | } |
208 | 177 | ||
209 | public void destroy() { | 178 | public void destroy() { |
210 | - //engine = null; | 179 | + sandboxService.release(this.scriptId); |
211 | } | 180 | } |
212 | } | 181 | } |
application/src/main/java/org/thingsboard/server/service/script/RuleNodeScriptFactory.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package org.thingsboard.server.service.script; | ||
18 | + | ||
19 | +public class RuleNodeScriptFactory { | ||
20 | + | ||
21 | + public static final String MSG = "msg"; | ||
22 | + public static final String METADATA = "metadata"; | ||
23 | + public static final String MSG_TYPE = "msgType"; | ||
24 | + public static final String RULE_NODE_FUNCTION_NAME = "ruleNodeFunc"; | ||
25 | + | ||
26 | + private static final String JS_WRAPPER_PREFIX_TEMPLATE = "function %s(msgStr, metadataStr, msgType) { " + | ||
27 | + " var msg = JSON.parse(msgStr); " + | ||
28 | + " var metadata = JSON.parse(metadataStr); " + | ||
29 | + " return JSON.stringify(%s(msg, metadata, msgType));" + | ||
30 | + " function %s(%s, %s, %s) {"; | ||
31 | + private static final String JS_WRAPPER_SUFFIX = "}" + | ||
32 | + "\n}"; | ||
33 | + | ||
34 | + | ||
35 | + public static String generateRuleNodeScript(String functionName, String scriptBody, String... argNames) { | ||
36 | + String msgArg; | ||
37 | + String metadataArg; | ||
38 | + String msgTypeArg; | ||
39 | + if (argNames != null && argNames.length == 3) { | ||
40 | + msgArg = argNames[0]; | ||
41 | + metadataArg = argNames[1]; | ||
42 | + msgTypeArg = argNames[2]; | ||
43 | + } else { | ||
44 | + msgArg = MSG; | ||
45 | + metadataArg = METADATA; | ||
46 | + msgTypeArg = MSG_TYPE; | ||
47 | + } | ||
48 | + String jsWrapperPrefix = String.format(JS_WRAPPER_PREFIX_TEMPLATE, functionName, | ||
49 | + RULE_NODE_FUNCTION_NAME, RULE_NODE_FUNCTION_NAME, msgArg, metadataArg, msgTypeArg); | ||
50 | + return jsWrapperPrefix + scriptBody + JS_WRAPPER_SUFFIX; | ||
51 | + } | ||
52 | + | ||
53 | +} |
@@ -243,6 +243,8 @@ actors: | @@ -243,6 +243,8 @@ actors: | ||
243 | monitor_thread_pool_size: "${ACTORS_RULE_JS_SANDBOX_MONITOR_THREAD_POOL_SIZE:4}" | 243 | monitor_thread_pool_size: "${ACTORS_RULE_JS_SANDBOX_MONITOR_THREAD_POOL_SIZE:4}" |
244 | # Maximum CPU time in milliseconds allowed for script execution | 244 | # Maximum CPU time in milliseconds allowed for script execution |
245 | max_cpu_time: "${ACTORS_RULE_JS_SANDBOX_MAX_CPU_TIME:100}" | 245 | max_cpu_time: "${ACTORS_RULE_JS_SANDBOX_MAX_CPU_TIME:100}" |
246 | + # Maximum allowed JavaScript execution errors before JavaScript will be blacklisted | ||
247 | + max_errors: "${ACTORS_RULE_JS_SANDBOX_MAX_ERRORS:3}" | ||
246 | chain: | 248 | chain: |
247 | # Errors for particular actor are persisted once per specified amount of milliseconds | 249 | # Errors for particular actor are persisted once per specified amount of milliseconds |
248 | error_persist_frequency: "${ACTORS_RULE_CHAIN_ERROR_FREQUENCY:3000}" | 250 | error_persist_frequency: "${ACTORS_RULE_CHAIN_ERROR_FREQUENCY:3000}" |
application/src/test/java/org/thingsboard/server/service/script/RuleNodeJsScriptEngineTest.java
renamed from
application/src/test/java/org/thingsboard/server/service/script/JsScriptEngineTest.java
@@ -27,30 +27,28 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; | @@ -27,30 +27,28 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; | ||
27 | import javax.script.ScriptException; | 27 | import javax.script.ScriptException; |
28 | 28 | ||
29 | import java.util.Set; | 29 | import java.util.Set; |
30 | -import java.util.concurrent.ExecutorService; | ||
31 | -import java.util.concurrent.Executors; | ||
32 | 30 | ||
33 | import static org.junit.Assert.*; | 31 | import static org.junit.Assert.*; |
34 | 32 | ||
35 | -public class JsScriptEngineTest { | 33 | +public class RuleNodeJsScriptEngineTest { |
36 | 34 | ||
37 | private ScriptEngine scriptEngine; | 35 | private ScriptEngine scriptEngine; |
38 | private TestNashornJsSandboxService jsSandboxService; | 36 | private TestNashornJsSandboxService jsSandboxService; |
39 | 37 | ||
40 | @Before | 38 | @Before |
41 | public void beforeTest() throws Exception { | 39 | public void beforeTest() throws Exception { |
42 | - jsSandboxService = new TestNashornJsSandboxService(1, 100); | 40 | + jsSandboxService = new TestNashornJsSandboxService(1, 100, 3); |
43 | } | 41 | } |
44 | 42 | ||
45 | @After | 43 | @After |
46 | public void afterTest() throws Exception { | 44 | public void afterTest() throws Exception { |
47 | - jsSandboxService.destroy(); | 45 | + jsSandboxService.stop(); |
48 | } | 46 | } |
49 | 47 | ||
50 | @Test | 48 | @Test |
51 | public void msgCanBeUpdated() throws ScriptException { | 49 | public void msgCanBeUpdated() throws ScriptException { |
52 | String function = "metadata.temp = metadata.temp * 10; return {metadata: metadata};"; | 50 | String function = "metadata.temp = metadata.temp * 10; return {metadata: metadata};"; |
53 | - scriptEngine = new JsScriptEngine(jsSandboxService, function, "Transform"); | 51 | + scriptEngine = new RuleNodeJsScriptEngine(jsSandboxService, function); |
54 | 52 | ||
55 | TbMsgMetaData metaData = new TbMsgMetaData(); | 53 | TbMsgMetaData metaData = new TbMsgMetaData(); |
56 | metaData.putValue("temp", "7"); | 54 | metaData.putValue("temp", "7"); |
@@ -61,12 +59,13 @@ public class JsScriptEngineTest { | @@ -61,12 +59,13 @@ public class JsScriptEngineTest { | ||
61 | 59 | ||
62 | TbMsg actual = scriptEngine.executeUpdate(msg); | 60 | TbMsg actual = scriptEngine.executeUpdate(msg); |
63 | assertEquals("70", actual.getMetaData().getValue("temp")); | 61 | assertEquals("70", actual.getMetaData().getValue("temp")); |
62 | + scriptEngine.destroy(); | ||
64 | } | 63 | } |
65 | 64 | ||
66 | @Test | 65 | @Test |
67 | public void newAttributesCanBeAddedInMsg() throws ScriptException { | 66 | public void newAttributesCanBeAddedInMsg() throws ScriptException { |
68 | String function = "metadata.newAttr = metadata.humidity - msg.passed; return {metadata: metadata};"; | 67 | String function = "metadata.newAttr = metadata.humidity - msg.passed; return {metadata: metadata};"; |
69 | - scriptEngine = new JsScriptEngine(jsSandboxService, function, "Transform"); | 68 | + scriptEngine = new RuleNodeJsScriptEngine(jsSandboxService, function); |
70 | TbMsgMetaData metaData = new TbMsgMetaData(); | 69 | TbMsgMetaData metaData = new TbMsgMetaData(); |
71 | metaData.putValue("temp", "7"); | 70 | metaData.putValue("temp", "7"); |
72 | metaData.putValue("humidity", "99"); | 71 | metaData.putValue("humidity", "99"); |
@@ -76,12 +75,13 @@ public class JsScriptEngineTest { | @@ -76,12 +75,13 @@ public class JsScriptEngineTest { | ||
76 | 75 | ||
77 | TbMsg actual = scriptEngine.executeUpdate(msg); | 76 | TbMsg actual = scriptEngine.executeUpdate(msg); |
78 | assertEquals("94", actual.getMetaData().getValue("newAttr")); | 77 | assertEquals("94", actual.getMetaData().getValue("newAttr")); |
78 | + scriptEngine.destroy(); | ||
79 | } | 79 | } |
80 | 80 | ||
81 | @Test | 81 | @Test |
82 | public void payloadCanBeUpdated() throws ScriptException { | 82 | public void payloadCanBeUpdated() throws ScriptException { |
83 | String function = "msg.passed = msg.passed * metadata.temp; msg.bigObj.newProp = 'Ukraine'; return {msg: msg};"; | 83 | String function = "msg.passed = msg.passed * metadata.temp; msg.bigObj.newProp = 'Ukraine'; return {msg: msg};"; |
84 | - scriptEngine = new JsScriptEngine(jsSandboxService, function, "Transform"); | 84 | + scriptEngine = new RuleNodeJsScriptEngine(jsSandboxService, function); |
85 | TbMsgMetaData metaData = new TbMsgMetaData(); | 85 | TbMsgMetaData metaData = new TbMsgMetaData(); |
86 | metaData.putValue("temp", "7"); | 86 | metaData.putValue("temp", "7"); |
87 | metaData.putValue("humidity", "99"); | 87 | metaData.putValue("humidity", "99"); |
@@ -93,12 +93,13 @@ public class JsScriptEngineTest { | @@ -93,12 +93,13 @@ public class JsScriptEngineTest { | ||
93 | 93 | ||
94 | String expectedJson = "{\"name\":\"Vit\",\"passed\":35,\"bigObj\":{\"prop\":42,\"newProp\":\"Ukraine\"}}"; | 94 | String expectedJson = "{\"name\":\"Vit\",\"passed\":35,\"bigObj\":{\"prop\":42,\"newProp\":\"Ukraine\"}}"; |
95 | assertEquals(expectedJson, actual.getData()); | 95 | assertEquals(expectedJson, actual.getData()); |
96 | + scriptEngine.destroy(); | ||
96 | } | 97 | } |
97 | 98 | ||
98 | @Test | 99 | @Test |
99 | public void metadataAccessibleForFilter() throws ScriptException { | 100 | public void metadataAccessibleForFilter() throws ScriptException { |
100 | String function = "return metadata.humidity < 15;"; | 101 | String function = "return metadata.humidity < 15;"; |
101 | - scriptEngine = new JsScriptEngine(jsSandboxService, function, "Filter"); | 102 | + scriptEngine = new RuleNodeJsScriptEngine(jsSandboxService, function); |
102 | TbMsgMetaData metaData = new TbMsgMetaData(); | 103 | TbMsgMetaData metaData = new TbMsgMetaData(); |
103 | metaData.putValue("temp", "7"); | 104 | metaData.putValue("temp", "7"); |
104 | metaData.putValue("humidity", "99"); | 105 | metaData.putValue("humidity", "99"); |
@@ -106,12 +107,13 @@ public class JsScriptEngineTest { | @@ -106,12 +107,13 @@ public class JsScriptEngineTest { | ||
106 | 107 | ||
107 | TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); | 108 | TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); |
108 | assertFalse(scriptEngine.executeFilter(msg)); | 109 | assertFalse(scriptEngine.executeFilter(msg)); |
110 | + scriptEngine.destroy(); | ||
109 | } | 111 | } |
110 | 112 | ||
111 | @Test | 113 | @Test |
112 | public void dataAccessibleForFilter() throws ScriptException { | 114 | public void dataAccessibleForFilter() throws ScriptException { |
113 | String function = "return msg.passed < 15 && msg.name === 'Vit' && metadata.temp == 7 && msg.bigObj.prop == 42;"; | 115 | String function = "return msg.passed < 15 && msg.name === 'Vit' && metadata.temp == 7 && msg.bigObj.prop == 42;"; |
114 | - scriptEngine = new JsScriptEngine(jsSandboxService, function, "Filter"); | 116 | + scriptEngine = new RuleNodeJsScriptEngine(jsSandboxService, function); |
115 | TbMsgMetaData metaData = new TbMsgMetaData(); | 117 | TbMsgMetaData metaData = new TbMsgMetaData(); |
116 | metaData.putValue("temp", "7"); | 118 | metaData.putValue("temp", "7"); |
117 | metaData.putValue("humidity", "99"); | 119 | metaData.putValue("humidity", "99"); |
@@ -119,6 +121,7 @@ public class JsScriptEngineTest { | @@ -119,6 +121,7 @@ public class JsScriptEngineTest { | ||
119 | 121 | ||
120 | TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); | 122 | TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); |
121 | assertTrue(scriptEngine.executeFilter(msg)); | 123 | assertTrue(scriptEngine.executeFilter(msg)); |
124 | + scriptEngine.destroy(); | ||
122 | } | 125 | } |
123 | 126 | ||
124 | @Test | 127 | @Test |
@@ -131,7 +134,7 @@ public class JsScriptEngineTest { | @@ -131,7 +134,7 @@ public class JsScriptEngineTest { | ||
131 | "};\n" + | 134 | "};\n" + |
132 | "\n" + | 135 | "\n" + |
133 | "return nextRelation(metadata, msg);"; | 136 | "return nextRelation(metadata, msg);"; |
134 | - scriptEngine = new JsScriptEngine(jsSandboxService, jsCode, "Switch"); | 137 | + scriptEngine = new RuleNodeJsScriptEngine(jsSandboxService, jsCode); |
135 | TbMsgMetaData metaData = new TbMsgMetaData(); | 138 | TbMsgMetaData metaData = new TbMsgMetaData(); |
136 | metaData.putValue("temp", "10"); | 139 | metaData.putValue("temp", "10"); |
137 | metaData.putValue("humidity", "99"); | 140 | metaData.putValue("humidity", "99"); |
@@ -140,6 +143,7 @@ public class JsScriptEngineTest { | @@ -140,6 +143,7 @@ public class JsScriptEngineTest { | ||
140 | TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); | 143 | TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); |
141 | Set<String> actual = scriptEngine.executeSwitch(msg); | 144 | Set<String> actual = scriptEngine.executeSwitch(msg); |
142 | assertEquals(Sets.newHashSet("one"), actual); | 145 | assertEquals(Sets.newHashSet("one"), actual); |
146 | + scriptEngine.destroy(); | ||
143 | } | 147 | } |
144 | 148 | ||
145 | @Test | 149 | @Test |
@@ -152,7 +156,7 @@ public class JsScriptEngineTest { | @@ -152,7 +156,7 @@ public class JsScriptEngineTest { | ||
152 | "};\n" + | 156 | "};\n" + |
153 | "\n" + | 157 | "\n" + |
154 | "return nextRelation(metadata, msg);"; | 158 | "return nextRelation(metadata, msg);"; |
155 | - scriptEngine = new JsScriptEngine(jsSandboxService, jsCode, "Switch"); | 159 | + scriptEngine = new RuleNodeJsScriptEngine(jsSandboxService, jsCode); |
156 | TbMsgMetaData metaData = new TbMsgMetaData(); | 160 | TbMsgMetaData metaData = new TbMsgMetaData(); |
157 | metaData.putValue("temp", "10"); | 161 | metaData.putValue("temp", "10"); |
158 | metaData.putValue("humidity", "99"); | 162 | metaData.putValue("humidity", "99"); |
@@ -161,6 +165,7 @@ public class JsScriptEngineTest { | @@ -161,6 +165,7 @@ public class JsScriptEngineTest { | ||
161 | TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); | 165 | TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); |
162 | Set<String> actual = scriptEngine.executeSwitch(msg); | 166 | Set<String> actual = scriptEngine.executeSwitch(msg); |
163 | assertEquals(Sets.newHashSet("one", "three"), actual); | 167 | assertEquals(Sets.newHashSet("one", "three"), actual); |
168 | + scriptEngine.destroy(); | ||
164 | } | 169 | } |
165 | 170 | ||
166 | } | 171 | } |
@@ -16,39 +16,40 @@ | @@ -16,39 +16,40 @@ | ||
16 | 16 | ||
17 | package org.thingsboard.server.service.script; | 17 | package org.thingsboard.server.service.script; |
18 | 18 | ||
19 | +import com.google.common.util.concurrent.ListenableFuture; | ||
19 | import delight.nashornsandbox.NashornSandbox; | 20 | import delight.nashornsandbox.NashornSandbox; |
20 | import delight.nashornsandbox.NashornSandboxes; | 21 | import delight.nashornsandbox.NashornSandboxes; |
21 | 22 | ||
22 | import javax.script.ScriptException; | 23 | import javax.script.ScriptException; |
24 | +import java.util.UUID; | ||
23 | import java.util.concurrent.ExecutorService; | 25 | import java.util.concurrent.ExecutorService; |
24 | import java.util.concurrent.Executors; | 26 | import java.util.concurrent.Executors; |
25 | 27 | ||
26 | -public class TestNashornJsSandboxService implements JsSandboxService { | 28 | +public class TestNashornJsSandboxService extends AbstractNashornJsSandboxService { |
27 | 29 | ||
28 | - private NashornSandbox sandbox = NashornSandboxes.create(); | ||
29 | - private ExecutorService monitorExecutorService; | 30 | + private final int monitorThreadPoolSize; |
31 | + private final long maxCpuTime; | ||
32 | + private final int maxErrors; | ||
30 | 33 | ||
31 | - public TestNashornJsSandboxService(int monitorThreadPoolSize, long maxCpuTime) { | ||
32 | - monitorExecutorService = Executors.newFixedThreadPool(monitorThreadPoolSize); | ||
33 | - sandbox.setExecutor(monitorExecutorService); | ||
34 | - sandbox.setMaxCPUTime(maxCpuTime); | ||
35 | - sandbox.allowNoBraces(false); | ||
36 | - sandbox.setMaxPreparedStatements(30); | 34 | + public TestNashornJsSandboxService(int monitorThreadPoolSize, long maxCpuTime, int maxErrors) { |
35 | + this.monitorThreadPoolSize = monitorThreadPoolSize; | ||
36 | + this.maxCpuTime = maxCpuTime; | ||
37 | + this.maxErrors = maxErrors; | ||
38 | + init(); | ||
37 | } | 39 | } |
38 | 40 | ||
39 | @Override | 41 | @Override |
40 | - public Object eval(String js) throws ScriptException { | ||
41 | - return sandbox.eval(js); | 42 | + protected int getMonitorThreadPoolSize() { |
43 | + return monitorThreadPoolSize; | ||
42 | } | 44 | } |
43 | 45 | ||
44 | @Override | 46 | @Override |
45 | - public Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException { | ||
46 | - return sandbox.getSandboxedInvocable().invokeFunction(name, args); | 47 | + protected long getMaxCpuTime() { |
48 | + return maxCpuTime; | ||
47 | } | 49 | } |
48 | 50 | ||
49 | - public void destroy() { | ||
50 | - if (monitorExecutorService != null) { | ||
51 | - monitorExecutorService.shutdownNow(); | ||
52 | - } | 51 | + @Override |
52 | + protected int getMaxErrors() { | ||
53 | + return maxErrors; | ||
53 | } | 54 | } |
54 | } | 55 | } |
@@ -90,6 +90,6 @@ public interface TbContext { | @@ -90,6 +90,6 @@ public interface TbContext { | ||
90 | 90 | ||
91 | MailService getMailService(); | 91 | MailService getMailService(); |
92 | 92 | ||
93 | - ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames); | 93 | + ScriptEngine createJsScriptEngine(String script, String... argNames); |
94 | 94 | ||
95 | } | 95 | } |
@@ -43,7 +43,7 @@ public abstract class TbAbstractAlarmNode<C extends TbAbstractAlarmNodeConfigura | @@ -43,7 +43,7 @@ public abstract class TbAbstractAlarmNode<C extends TbAbstractAlarmNodeConfigura | ||
43 | @Override | 43 | @Override |
44 | public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { | 44 | public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { |
45 | this.config = loadAlarmNodeConfig(configuration); | 45 | this.config = loadAlarmNodeConfig(configuration); |
46 | - this.buildDetailsJsEngine = ctx.createJsScriptEngine(config.getAlarmDetailsBuildJs(), "Details"); | 46 | + this.buildDetailsJsEngine = ctx.createJsScriptEngine(config.getAlarmDetailsBuildJs()); |
47 | } | 47 | } |
48 | 48 | ||
49 | protected abstract C loadAlarmNodeConfig(TbNodeConfiguration configuration) throws TbNodeException; | 49 | protected abstract C loadAlarmNodeConfig(TbNodeConfiguration configuration) throws TbNodeException; |
@@ -46,7 +46,7 @@ public class TbLogNode implements TbNode { | @@ -46,7 +46,7 @@ public class TbLogNode implements TbNode { | ||
46 | @Override | 46 | @Override |
47 | public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { | 47 | public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { |
48 | this.config = TbNodeUtils.convert(configuration, TbLogNodeConfiguration.class); | 48 | this.config = TbNodeUtils.convert(configuration, TbLogNodeConfiguration.class); |
49 | - this.jsEngine = ctx.createJsScriptEngine(config.getJsScript(), "ToString"); | 49 | + this.jsEngine = ctx.createJsScriptEngine(config.getJsScript()); |
50 | } | 50 | } |
51 | 51 | ||
52 | @Override | 52 | @Override |
@@ -65,7 +65,7 @@ public class TbMsgGeneratorNode implements TbNode { | @@ -65,7 +65,7 @@ public class TbMsgGeneratorNode implements TbNode { | ||
65 | } else { | 65 | } else { |
66 | originatorId = ctx.getSelfId(); | 66 | originatorId = ctx.getSelfId(); |
67 | } | 67 | } |
68 | - this.jsEngine = ctx.createJsScriptEngine(config.getJsScript(), "Generate", "prevMsg", "prevMetadata", "prevMsgType"); | 68 | + this.jsEngine = ctx.createJsScriptEngine(config.getJsScript(), "prevMsg", "prevMetadata", "prevMsgType"); |
69 | sentTickMsg(ctx); | 69 | sentTickMsg(ctx); |
70 | } | 70 | } |
71 | 71 |
@@ -45,7 +45,7 @@ public class TbJsFilterNode implements TbNode { | @@ -45,7 +45,7 @@ public class TbJsFilterNode implements TbNode { | ||
45 | @Override | 45 | @Override |
46 | public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { | 46 | public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { |
47 | this.config = TbNodeUtils.convert(configuration, TbJsFilterNodeConfiguration.class); | 47 | this.config = TbNodeUtils.convert(configuration, TbJsFilterNodeConfiguration.class); |
48 | - this.jsEngine = ctx.createJsScriptEngine(config.getJsScript(), "Filter"); | 48 | + this.jsEngine = ctx.createJsScriptEngine(config.getJsScript()); |
49 | } | 49 | } |
50 | 50 | ||
51 | @Override | 51 | @Override |
@@ -47,7 +47,7 @@ public class TbJsSwitchNode implements TbNode { | @@ -47,7 +47,7 @@ public class TbJsSwitchNode implements TbNode { | ||
47 | @Override | 47 | @Override |
48 | public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { | 48 | public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { |
49 | this.config = TbNodeUtils.convert(configuration, TbJsSwitchNodeConfiguration.class); | 49 | this.config = TbNodeUtils.convert(configuration, TbJsSwitchNodeConfiguration.class); |
50 | - this.jsEngine = ctx.createJsScriptEngine(config.getJsScript(), "Switch"); | 50 | + this.jsEngine = ctx.createJsScriptEngine(config.getJsScript()); |
51 | } | 51 | } |
52 | 52 | ||
53 | @Override | 53 | @Override |
@@ -43,7 +43,7 @@ public class TbTransformMsgNode extends TbAbstractTransformNode { | @@ -43,7 +43,7 @@ public class TbTransformMsgNode extends TbAbstractTransformNode { | ||
43 | @Override | 43 | @Override |
44 | public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { | 44 | public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { |
45 | this.config = TbNodeUtils.convert(configuration, TbTransformMsgNodeConfiguration.class); | 45 | this.config = TbNodeUtils.convert(configuration, TbTransformMsgNodeConfiguration.class); |
46 | - this.jsEngine = ctx.createJsScriptEngine(config.getJsScript(), "Transform"); | 46 | + this.jsEngine = ctx.createJsScriptEngine(config.getJsScript()); |
47 | setConfig(config); | 47 | setConfig(config); |
48 | } | 48 | } |
49 | 49 |
@@ -152,7 +152,7 @@ public class TbAlarmNodeTest { | @@ -152,7 +152,7 @@ public class TbAlarmNodeTest { | ||
152 | 152 | ||
153 | verifyError(msg, "message", NotImplementedException.class); | 153 | verifyError(msg, "message", NotImplementedException.class); |
154 | 154 | ||
155 | - verify(ctx).createJsScriptEngine("DETAILS", "Details"); | 155 | + verify(ctx).createJsScriptEngine("DETAILS"); |
156 | verify(ctx, times(1)).getJsExecutor(); | 156 | verify(ctx, times(1)).getJsExecutor(); |
157 | verify(ctx).getAlarmService(); | 157 | verify(ctx).getAlarmService(); |
158 | verify(ctx, times(2)).getDbCallbackExecutor(); | 158 | verify(ctx, times(2)).getDbCallbackExecutor(); |
@@ -314,7 +314,7 @@ public class TbAlarmNodeTest { | @@ -314,7 +314,7 @@ public class TbAlarmNodeTest { | ||
314 | ObjectMapper mapper = new ObjectMapper(); | 314 | ObjectMapper mapper = new ObjectMapper(); |
315 | TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); | 315 | TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); |
316 | 316 | ||
317 | - when(ctx.createJsScriptEngine("DETAILS", "Details")).thenReturn(detailsJs); | 317 | + when(ctx.createJsScriptEngine("DETAILS")).thenReturn(detailsJs); |
318 | 318 | ||
319 | when(ctx.getTenantId()).thenReturn(tenantId); | 319 | when(ctx.getTenantId()).thenReturn(tenantId); |
320 | when(ctx.getJsExecutor()).thenReturn(executor); | 320 | when(ctx.getJsExecutor()).thenReturn(executor); |
@@ -338,7 +338,7 @@ public class TbAlarmNodeTest { | @@ -338,7 +338,7 @@ public class TbAlarmNodeTest { | ||
338 | ObjectMapper mapper = new ObjectMapper(); | 338 | ObjectMapper mapper = new ObjectMapper(); |
339 | TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); | 339 | TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); |
340 | 340 | ||
341 | - when(ctx.createJsScriptEngine("DETAILS", "Details")).thenReturn(detailsJs); | 341 | + when(ctx.createJsScriptEngine("DETAILS")).thenReturn(detailsJs); |
342 | 342 | ||
343 | when(ctx.getTenantId()).thenReturn(tenantId); | 343 | when(ctx.getTenantId()).thenReturn(tenantId); |
344 | when(ctx.getJsExecutor()).thenReturn(executor); | 344 | when(ctx.getJsExecutor()).thenReturn(executor); |
@@ -97,7 +97,7 @@ public class TbJsFilterNodeTest { | @@ -97,7 +97,7 @@ public class TbJsFilterNodeTest { | ||
97 | ObjectMapper mapper = new ObjectMapper(); | 97 | ObjectMapper mapper = new ObjectMapper(); |
98 | TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); | 98 | TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); |
99 | 99 | ||
100 | - when(ctx.createJsScriptEngine("scr", "Filter")).thenReturn(scriptEngine); | 100 | + when(ctx.createJsScriptEngine("scr")).thenReturn(scriptEngine); |
101 | 101 | ||
102 | node = new TbJsFilterNode(); | 102 | node = new TbJsFilterNode(); |
103 | node.init(ctx, nodeConfiguration); | 103 | node.init(ctx, nodeConfiguration); |
@@ -79,7 +79,7 @@ public class TbJsSwitchNodeTest { | @@ -79,7 +79,7 @@ public class TbJsSwitchNodeTest { | ||
79 | ObjectMapper mapper = new ObjectMapper(); | 79 | ObjectMapper mapper = new ObjectMapper(); |
80 | TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); | 80 | TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); |
81 | 81 | ||
82 | - when(ctx.createJsScriptEngine("scr", "Switch")).thenReturn(scriptEngine); | 82 | + when(ctx.createJsScriptEngine("scr")).thenReturn(scriptEngine); |
83 | 83 | ||
84 | node = new TbJsSwitchNode(); | 84 | node = new TbJsSwitchNode(); |
85 | node.init(ctx, nodeConfiguration); | 85 | node.init(ctx, nodeConfiguration); |
@@ -97,7 +97,7 @@ public class TbTransformMsgNodeTest { | @@ -97,7 +97,7 @@ public class TbTransformMsgNodeTest { | ||
97 | ObjectMapper mapper = new ObjectMapper(); | 97 | ObjectMapper mapper = new ObjectMapper(); |
98 | TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); | 98 | TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); |
99 | 99 | ||
100 | - when(ctx.createJsScriptEngine("scr", "Transform")).thenReturn(scriptEngine); | 100 | + when(ctx.createJsScriptEngine("scr")).thenReturn(scriptEngine); |
101 | 101 | ||
102 | node = new TbTransformMsgNode(); | 102 | node = new TbTransformMsgNode(); |
103 | node.init(ctx, nodeConfiguration); | 103 | node.init(ctx, nodeConfiguration); |