Commit 04432ee73fdd612e75c1fe388e7039c6b768e8d6

Authored by Igor Kulikov
1 parent 02f24ca6

JavaScript sandbox service.

@@ -256,6 +256,10 @@ @@ -256,6 +256,10 @@
256 <groupId>org.hsqldb</groupId> 256 <groupId>org.hsqldb</groupId>
257 <artifactId>hsqldb</artifactId> 257 <artifactId>hsqldb</artifactId>
258 </dependency> 258 </dependency>
  259 + <dependency>
  260 + <groupId>org.javadelight</groupId>
  261 + <artifactId>delight-nashorn-sandbox</artifactId>
  262 + </dependency>
259 </dependencies> 263 </dependencies>
260 264
261 <build> 265 <build>
@@ -62,6 +62,7 @@ import org.thingsboard.server.service.mail.MailExecutorService; @@ -62,6 +62,7 @@ import org.thingsboard.server.service.mail.MailExecutorService;
62 import org.thingsboard.server.service.queue.MsgQueueService; 62 import org.thingsboard.server.service.queue.MsgQueueService;
63 import org.thingsboard.server.service.rpc.DeviceRpcService; 63 import org.thingsboard.server.service.rpc.DeviceRpcService;
64 import org.thingsboard.server.service.script.JsExecutorService; 64 import org.thingsboard.server.service.script.JsExecutorService;
  65 +import org.thingsboard.server.service.script.JsSandboxService;
65 import org.thingsboard.server.service.state.DeviceStateService; 66 import org.thingsboard.server.service.state.DeviceStateService;
66 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; 67 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
67 68
@@ -164,6 +165,10 @@ public class ActorSystemContext { @@ -164,6 +165,10 @@ public class ActorSystemContext {
164 165
165 @Autowired 166 @Autowired
166 @Getter 167 @Getter
  168 + private JsSandboxService jsSandbox;
  169 +
  170 + @Autowired
  171 + @Getter
167 private JsExecutorService jsExecutor; 172 private JsExecutorService jsExecutor;
168 173
169 @Autowired 174 @Autowired
@@ -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.NashornJsEngine; 47 +import org.thingsboard.server.service.script.JsScriptEngine;
48 import scala.concurrent.duration.Duration; 48 import scala.concurrent.duration.Duration;
49 49
50 import java.util.Collections; 50 import java.util.Collections;
@@ -152,7 +152,7 @@ class DefaultTbContext implements TbContext { @@ -152,7 +152,7 @@ class DefaultTbContext implements TbContext {
152 152
153 @Override 153 @Override
154 public ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames) { 154 public ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames) {
155 - return new NashornJsEngine(script, functionName, argNames); 155 + return new JsScriptEngine(mainCtx.getJsSandbox(), script, functionName, argNames);
156 } 156 }
157 157
158 @Override 158 @Override
@@ -50,7 +50,9 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; @@ -50,7 +50,9 @@ 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.NashornJsEngine; 53 +import org.thingsboard.server.service.script.JsExecutorService;
  54 +import org.thingsboard.server.service.script.JsSandboxService;
  55 +import org.thingsboard.server.service.script.JsScriptEngine;
54 56
55 import java.util.List; 57 import java.util.List;
56 import java.util.Map; 58 import java.util.Map;
@@ -69,6 +71,9 @@ public class RuleChainController extends BaseController { @@ -69,6 +71,9 @@ public class RuleChainController extends BaseController {
69 @Autowired 71 @Autowired
70 private EventService eventService; 72 private EventService eventService;
71 73
  74 + @Autowired
  75 + private JsSandboxService jsSandboxService;
  76 +
72 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") 77 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
73 @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET) 78 @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET)
74 @ResponseBody 79 @ResponseBody
@@ -273,7 +278,7 @@ public class RuleChainController extends BaseController { @@ -273,7 +278,7 @@ public class RuleChainController extends BaseController {
273 String errorText = ""; 278 String errorText = "";
274 ScriptEngine engine = null; 279 ScriptEngine engine = null;
275 try { 280 try {
276 - engine = new NashornJsEngine(script, functionName, argNames); 281 + engine = new JsScriptEngine(jsSandboxService, script, functionName, argNames);
277 TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data, null, null, 0L); 282 TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data, null, null, 0L);
278 switch (scriptType) { 283 switch (scriptType) {
279 case "update": 284 case "update":
@@ -54,6 +54,10 @@ public abstract class AbstractListeningExecutor implements ListeningExecutor { @@ -54,6 +54,10 @@ public abstract class AbstractListeningExecutor implements ListeningExecutor {
54 service.execute(command); 54 service.execute(command);
55 } 55 }
56 56
  57 + public ListeningExecutorService executor() {
  58 + return service;
  59 + }
  60 +
57 protected abstract int getThreadPollSize(); 61 protected abstract int getThreadPollSize();
58 62
59 } 63 }
  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 javax.script.ScriptException;
  20 +
  21 +public interface JsSandboxService {
  22 +
  23 + Object eval(String js) throws ScriptException;
  24 +
  25 + Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException;
  26 +
  27 +}
application/src/main/java/org/thingsboard/server/service/script/JsScriptEngine.java renamed from application/src/main/java/org/thingsboard/server/service/script/NashornJsEngine.java
@@ -19,14 +19,11 @@ import com.fasterxml.jackson.core.type.TypeReference; @@ -19,14 +19,11 @@ import com.fasterxml.jackson.core.type.TypeReference;
19 import com.fasterxml.jackson.databind.JsonNode; 19 import com.fasterxml.jackson.databind.JsonNode;
20 import com.fasterxml.jackson.databind.ObjectMapper; 20 import com.fasterxml.jackson.databind.ObjectMapper;
21 import com.google.common.collect.Sets; 21 import com.google.common.collect.Sets;
22 -import jdk.nashorn.api.scripting.NashornScriptEngineFactory;  
23 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
24 import org.apache.commons.lang3.StringUtils; 23 import org.apache.commons.lang3.StringUtils;
25 import org.thingsboard.server.common.msg.TbMsg; 24 import org.thingsboard.server.common.msg.TbMsg;
26 import org.thingsboard.server.common.msg.TbMsgMetaData; 25 import org.thingsboard.server.common.msg.TbMsgMetaData;
27 26
28 -import javax.script.Invocable;  
29 -import javax.script.ScriptEngine;  
30 import javax.script.ScriptException; 27 import javax.script.ScriptException;
31 import java.util.Collections; 28 import java.util.Collections;
32 import java.util.Map; 29 import java.util.Map;
@@ -34,7 +31,7 @@ import java.util.Set; @@ -34,7 +31,7 @@ import java.util.Set;
34 31
35 32
36 @Slf4j 33 @Slf4j
37 -public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEngine { 34 +public class JsScriptEngine implements org.thingsboard.rule.engine.api.ScriptEngine {
38 35
39 public static final String MSG = "msg"; 36 public static final String MSG = "msg";
40 public static final String METADATA = "metadata"; 37 public static final String METADATA = "metadata";
@@ -49,12 +46,14 @@ public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEn @@ -49,12 +46,14 @@ public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEn
49 "\n}"; 46 "\n}";
50 47
51 private static final ObjectMapper mapper = new ObjectMapper(); 48 private static final ObjectMapper mapper = new ObjectMapper();
52 - private static NashornScriptEngineFactory factory = new NashornScriptEngineFactory();  
53 - private ScriptEngine engine = factory.getScriptEngine(new String[]{"--no-java"}); 49 +// private static NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
  50 +// private ScriptEngine engine = factory.getScriptEngine(new String[]{"--no-java"});
  51 + private final JsSandboxService sandboxService;
54 52
55 private final String invokeFunctionName; 53 private final String invokeFunctionName;
56 54
57 - public NashornJsEngine(String script, String functionName, String... argNames) { 55 + public JsScriptEngine(JsSandboxService sandboxService, String script, String functionName, String... argNames) {
  56 + this.sandboxService = sandboxService;
58 this.invokeFunctionName = "invokeInternal" + this.hashCode(); 57 this.invokeFunctionName = "invokeInternal" + this.hashCode();
59 String msgArg; 58 String msgArg;
60 String metadataArg; 59 String metadataArg;
@@ -75,7 +74,8 @@ public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEn @@ -75,7 +74,8 @@ public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEn
75 74
76 private void compileScript(String script) { 75 private void compileScript(String script) {
77 try { 76 try {
78 - engine.eval(script); 77 + //engine.eval(script);
  78 + sandboxService.eval(script);
79 } catch (ScriptException e) { 79 } catch (ScriptException e) {
80 log.warn("Failed to compile JS script: {}", e.getMessage(), e); 80 log.warn("Failed to compile JS script: {}", e.getMessage(), e);
81 throw new IllegalArgumentException("Can't compile script: " + e.getMessage()); 81 throw new IllegalArgumentException("Can't compile script: " + e.getMessage());
@@ -195,7 +195,8 @@ public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEn @@ -195,7 +195,8 @@ public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEn
195 private JsonNode executeScript(TbMsg msg) throws ScriptException { 195 private JsonNode executeScript(TbMsg msg) throws ScriptException {
196 try { 196 try {
197 String[] inArgs = prepareArgs(msg); 197 String[] inArgs = prepareArgs(msg);
198 - String eval = ((Invocable)engine).invokeFunction(this.invokeFunctionName, inArgs[0], inArgs[1], inArgs[2]).toString(); 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();
199 return mapper.readTree(eval); 200 return mapper.readTree(eval);
200 } catch (ScriptException | IllegalArgumentException th) { 201 } catch (ScriptException | IllegalArgumentException th) {
201 throw th; 202 throw th;
@@ -206,6 +207,6 @@ public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEn @@ -206,6 +207,6 @@ public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEn
206 } 207 }
207 208
208 public void destroy() { 209 public void destroy() {
209 - engine = null; 210 + //engine = null;
210 } 211 }
211 } 212 }
  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 delight.nashornsandbox.NashornSandbox;
  20 +import delight.nashornsandbox.NashornSandboxes;
  21 +import lombok.extern.slf4j.Slf4j;
  22 +import org.springframework.beans.factory.annotation.Value;
  23 +import org.springframework.stereotype.Service;
  24 +
  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
  32 +@Service
  33 +public class NashornJsSandboxService implements JsSandboxService {
  34 +
  35 + @Value("${actors.rule.js_sandbox.monitor_thread_pool_size}")
  36 + private int monitorThreadPoolSize;
  37 +
  38 + @Value("${actors.rule.js_sandbox.max_cpu_time}")
  39 + private long maxCpuTime;
  40 +
  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 + }
  52 +
  53 + @PreDestroy
  54 + public void stop() {
  55 + if (monitorExecutorService != null) {
  56 + monitorExecutorService.shutdownNow();
  57 + }
  58 + }
  59 +
  60 + @Override
  61 + public Object eval(String js) throws ScriptException {
  62 + return sandbox.eval(js);
  63 + }
  64 +
  65 + @Override
  66 + public Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException {
  67 + return sandbox.getSandboxedInvocable().invokeFunction(name, args);
  68 + }
  69 +
  70 +}
@@ -238,6 +238,11 @@ actors: @@ -238,6 +238,11 @@ actors:
238 mail_thread_pool_size: "${ACTORS_RULE_MAIL_THREAD_POOL_SIZE:10}" 238 mail_thread_pool_size: "${ACTORS_RULE_MAIL_THREAD_POOL_SIZE:10}"
239 # Specify thread pool size for external call service 239 # Specify thread pool size for external call service
240 external_call_thread_pool_size: "${ACTORS_RULE_EXTERNAL_CALL_THREAD_POOL_SIZE:10}" 240 external_call_thread_pool_size: "${ACTORS_RULE_EXTERNAL_CALL_THREAD_POOL_SIZE:10}"
  241 + js_sandbox:
  242 + # Specify thread pool size for JavaScript sandbox resource monitor
  243 + monitor_thread_pool_size: "${ACTORS_RULE_JS_SANDBOX_MONITOR_THREAD_POOL_SIZE:4}"
  244 + # Maximum CPU time in milliseconds allowed for script execution
  245 + max_cpu_time: "${ACTORS_RULE_JS_SANDBOX_MAX_CPU_TIME:100}"
241 chain: 246 chain:
242 # Errors for particular actor are persisted once per specified amount of milliseconds 247 # Errors for particular actor are persisted once per specified amount of milliseconds
243 error_persist_frequency: "${ACTORS_RULE_CHAIN_ERROR_FREQUENCY:3000}" 248 error_persist_frequency: "${ACTORS_RULE_CHAIN_ERROR_FREQUENCY:3000}"
application/src/test/java/org/thingsboard/server/service/script/JsScriptEngineTest.java renamed from application/src/test/java/org/thingsboard/server/service/script/NashornJsEngineTest.java
@@ -17,6 +17,8 @@ package org.thingsboard.server.service.script; @@ -17,6 +17,8 @@ package org.thingsboard.server.service.script;
17 17
18 import com.datastax.driver.core.utils.UUIDs; 18 import com.datastax.driver.core.utils.UUIDs;
19 import com.google.common.collect.Sets; 19 import com.google.common.collect.Sets;
  20 +import org.junit.After;
  21 +import org.junit.Before;
20 import org.junit.Test; 22 import org.junit.Test;
21 import org.thingsboard.rule.engine.api.ScriptEngine; 23 import org.thingsboard.rule.engine.api.ScriptEngine;
22 import org.thingsboard.server.common.msg.TbMsg; 24 import org.thingsboard.server.common.msg.TbMsg;
@@ -25,17 +27,30 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -25,17 +27,30 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
25 import javax.script.ScriptException; 27 import javax.script.ScriptException;
26 28
27 import java.util.Set; 29 import java.util.Set;
  30 +import java.util.concurrent.ExecutorService;
  31 +import java.util.concurrent.Executors;
28 32
29 import static org.junit.Assert.*; 33 import static org.junit.Assert.*;
30 34
31 -public class NashornJsEngineTest { 35 +public class JsScriptEngineTest {
32 36
33 private ScriptEngine scriptEngine; 37 private ScriptEngine scriptEngine;
  38 + private TestNashornJsSandboxService jsSandboxService;
  39 +
  40 + @Before
  41 + public void beforeTest() throws Exception {
  42 + jsSandboxService = new TestNashornJsSandboxService(1, 100);
  43 + }
  44 +
  45 + @After
  46 + public void afterTest() throws Exception {
  47 + jsSandboxService.destroy();
  48 + }
34 49
35 @Test 50 @Test
36 public void msgCanBeUpdated() throws ScriptException { 51 public void msgCanBeUpdated() throws ScriptException {
37 String function = "metadata.temp = metadata.temp * 10; return {metadata: metadata};"; 52 String function = "metadata.temp = metadata.temp * 10; return {metadata: metadata};";
38 - scriptEngine = new NashornJsEngine(function, "Transform"); 53 + scriptEngine = new JsScriptEngine(jsSandboxService, function, "Transform");
39 54
40 TbMsgMetaData metaData = new TbMsgMetaData(); 55 TbMsgMetaData metaData = new TbMsgMetaData();
41 metaData.putValue("temp", "7"); 56 metaData.putValue("temp", "7");
@@ -51,7 +66,7 @@ public class NashornJsEngineTest { @@ -51,7 +66,7 @@ public class NashornJsEngineTest {
51 @Test 66 @Test
52 public void newAttributesCanBeAddedInMsg() throws ScriptException { 67 public void newAttributesCanBeAddedInMsg() throws ScriptException {
53 String function = "metadata.newAttr = metadata.humidity - msg.passed; return {metadata: metadata};"; 68 String function = "metadata.newAttr = metadata.humidity - msg.passed; return {metadata: metadata};";
54 - scriptEngine = new NashornJsEngine(function, "Transform"); 69 + scriptEngine = new JsScriptEngine(jsSandboxService, function, "Transform");
55 TbMsgMetaData metaData = new TbMsgMetaData(); 70 TbMsgMetaData metaData = new TbMsgMetaData();
56 metaData.putValue("temp", "7"); 71 metaData.putValue("temp", "7");
57 metaData.putValue("humidity", "99"); 72 metaData.putValue("humidity", "99");
@@ -66,7 +81,7 @@ public class NashornJsEngineTest { @@ -66,7 +81,7 @@ public class NashornJsEngineTest {
66 @Test 81 @Test
67 public void payloadCanBeUpdated() throws ScriptException { 82 public void payloadCanBeUpdated() throws ScriptException {
68 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};";
69 - scriptEngine = new NashornJsEngine(function, "Transform"); 84 + scriptEngine = new JsScriptEngine(jsSandboxService, function, "Transform");
70 TbMsgMetaData metaData = new TbMsgMetaData(); 85 TbMsgMetaData metaData = new TbMsgMetaData();
71 metaData.putValue("temp", "7"); 86 metaData.putValue("temp", "7");
72 metaData.putValue("humidity", "99"); 87 metaData.putValue("humidity", "99");
@@ -83,7 +98,7 @@ public class NashornJsEngineTest { @@ -83,7 +98,7 @@ public class NashornJsEngineTest {
83 @Test 98 @Test
84 public void metadataAccessibleForFilter() throws ScriptException { 99 public void metadataAccessibleForFilter() throws ScriptException {
85 String function = "return metadata.humidity < 15;"; 100 String function = "return metadata.humidity < 15;";
86 - scriptEngine = new NashornJsEngine(function, "Filter"); 101 + scriptEngine = new JsScriptEngine(jsSandboxService, function, "Filter");
87 TbMsgMetaData metaData = new TbMsgMetaData(); 102 TbMsgMetaData metaData = new TbMsgMetaData();
88 metaData.putValue("temp", "7"); 103 metaData.putValue("temp", "7");
89 metaData.putValue("humidity", "99"); 104 metaData.putValue("humidity", "99");
@@ -96,7 +111,7 @@ public class NashornJsEngineTest { @@ -96,7 +111,7 @@ public class NashornJsEngineTest {
96 @Test 111 @Test
97 public void dataAccessibleForFilter() throws ScriptException { 112 public void dataAccessibleForFilter() throws ScriptException {
98 String function = "return msg.passed < 15 && msg.name === 'Vit' && metadata.temp == 7 && msg.bigObj.prop == 42;"; 113 String function = "return msg.passed < 15 && msg.name === 'Vit' && metadata.temp == 7 && msg.bigObj.prop == 42;";
99 - scriptEngine = new NashornJsEngine(function, "Filter"); 114 + scriptEngine = new JsScriptEngine(jsSandboxService, function, "Filter");
100 TbMsgMetaData metaData = new TbMsgMetaData(); 115 TbMsgMetaData metaData = new TbMsgMetaData();
101 metaData.putValue("temp", "7"); 116 metaData.putValue("temp", "7");
102 metaData.putValue("humidity", "99"); 117 metaData.putValue("humidity", "99");
@@ -116,7 +131,7 @@ public class NashornJsEngineTest { @@ -116,7 +131,7 @@ public class NashornJsEngineTest {
116 "};\n" + 131 "};\n" +
117 "\n" + 132 "\n" +
118 "return nextRelation(metadata, msg);"; 133 "return nextRelation(metadata, msg);";
119 - scriptEngine = new NashornJsEngine(jsCode, "Switch"); 134 + scriptEngine = new JsScriptEngine(jsSandboxService, jsCode, "Switch");
120 TbMsgMetaData metaData = new TbMsgMetaData(); 135 TbMsgMetaData metaData = new TbMsgMetaData();
121 metaData.putValue("temp", "10"); 136 metaData.putValue("temp", "10");
122 metaData.putValue("humidity", "99"); 137 metaData.putValue("humidity", "99");
@@ -137,7 +152,7 @@ public class NashornJsEngineTest { @@ -137,7 +152,7 @@ public class NashornJsEngineTest {
137 "};\n" + 152 "};\n" +
138 "\n" + 153 "\n" +
139 "return nextRelation(metadata, msg);"; 154 "return nextRelation(metadata, msg);";
140 - scriptEngine = new NashornJsEngine(jsCode, "Switch"); 155 + scriptEngine = new JsScriptEngine(jsSandboxService, jsCode, "Switch");
141 TbMsgMetaData metaData = new TbMsgMetaData(); 156 TbMsgMetaData metaData = new TbMsgMetaData();
142 metaData.putValue("temp", "10"); 157 metaData.putValue("temp", "10");
143 metaData.putValue("humidity", "99"); 158 metaData.putValue("humidity", "99");
  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 delight.nashornsandbox.NashornSandbox;
  20 +import delight.nashornsandbox.NashornSandboxes;
  21 +
  22 +import javax.script.ScriptException;
  23 +import java.util.concurrent.ExecutorService;
  24 +import java.util.concurrent.Executors;
  25 +
  26 +public class TestNashornJsSandboxService implements JsSandboxService {
  27 +
  28 + private NashornSandbox sandbox = NashornSandboxes.create();
  29 + private ExecutorService monitorExecutorService;
  30 +
  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);
  37 + }
  38 +
  39 + @Override
  40 + public Object eval(String js) throws ScriptException {
  41 + return sandbox.eval(js);
  42 + }
  43 +
  44 + @Override
  45 + public Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException {
  46 + return sandbox.getSandboxedInvocable().invokeFunction(name, args);
  47 + }
  48 +
  49 + public void destroy() {
  50 + if (monitorExecutorService != null) {
  51 + monitorExecutorService.shutdownNow();
  52 + }
  53 + }
  54 +}
@@ -81,6 +81,7 @@ @@ -81,6 +81,7 @@
81 org/thingsboard/server/extensions/core/plugin/telemetry/gen/**/* 81 org/thingsboard/server/extensions/core/plugin/telemetry/gen/**/*
82 </sonar.exclusions> 82 </sonar.exclusions>
83 <elasticsearch.version>5.0.2</elasticsearch.version> 83 <elasticsearch.version>5.0.2</elasticsearch.version>
  84 + <delight-nashorn-sandbox.version>0.1.14</delight-nashorn-sandbox.version>
84 </properties> 85 </properties>
85 86
86 <modules> 87 <modules>
@@ -814,6 +815,11 @@ @@ -814,6 +815,11 @@
814 <artifactId>rest</artifactId> 815 <artifactId>rest</artifactId>
815 <version>${elasticsearch.version}</version> 816 <version>${elasticsearch.version}</version>
816 </dependency> 817 </dependency>
  818 + <dependency>
  819 + <groupId>org.javadelight</groupId>
  820 + <artifactId>delight-nashorn-sandbox</artifactId>
  821 + <version>${delight-nashorn-sandbox.version}</version>
  822 + </dependency>
817 </dependencies> 823 </dependencies>
818 </dependencyManagement> 824 </dependencyManagement>
819 825