thingsboard-aplcache
Changes
application/pom.xml 4(+4 -0)
application/src/main/java/org/thingsboard/server/service/executors/AbstractListeningExecutor.java 4(+4 -0)
application/src/main/java/org/thingsboard/server/service/script/NashornJsSandboxService.java 70(+70 -0)
application/src/test/java/org/thingsboard/server/service/script/TestNashornJsSandboxService.java 54(+54 -0)
pom.xml 6(+6 -0)
Details
application/pom.xml 4(+4 -0)
diff --git a/application/pom.xml b/application/pom.xml
index 45e6f23..e0b6b98 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -256,6 +256,10 @@
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.javadelight</groupId>
+ <artifactId>delight-nashorn-sandbox</artifactId>
+ </dependency>
</dependencies>
<build>
diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
index 6986f62..f7c7f1a 100644
--- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
+++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
@@ -62,6 +62,7 @@ import org.thingsboard.server.service.mail.MailExecutorService;
import org.thingsboard.server.service.queue.MsgQueueService;
import org.thingsboard.server.service.rpc.DeviceRpcService;
import org.thingsboard.server.service.script.JsExecutorService;
+import org.thingsboard.server.service.script.JsSandboxService;
import org.thingsboard.server.service.state.DeviceStateService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
@@ -164,6 +165,10 @@ public class ActorSystemContext {
@Autowired
@Getter
+ private JsSandboxService jsSandbox;
+
+ @Autowired
+ @Getter
private JsExecutorService jsExecutor;
@Autowired
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
index 6501fdc..a8b66dc 100644
--- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
@@ -44,7 +44,7 @@ import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.dao.user.UserService;
-import org.thingsboard.server.service.script.NashornJsEngine;
+import org.thingsboard.server.service.script.JsScriptEngine;
import scala.concurrent.duration.Duration;
import java.util.Collections;
@@ -152,7 +152,7 @@ class DefaultTbContext implements TbContext {
@Override
public ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames) {
- return new NashornJsEngine(script, functionName, argNames);
+ return new JsScriptEngine(mainCtx.getJsSandbox(), script, functionName, argNames);
}
@Override
diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
index 68482b3..e8a5f8d 100644
--- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
@@ -50,7 +50,9 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.event.EventService;
-import org.thingsboard.server.service.script.NashornJsEngine;
+import org.thingsboard.server.service.script.JsExecutorService;
+import org.thingsboard.server.service.script.JsSandboxService;
+import org.thingsboard.server.service.script.JsScriptEngine;
import java.util.List;
import java.util.Map;
@@ -69,6 +71,9 @@ public class RuleChainController extends BaseController {
@Autowired
private EventService eventService;
+ @Autowired
+ private JsSandboxService jsSandboxService;
+
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET)
@ResponseBody
@@ -273,7 +278,7 @@ public class RuleChainController extends BaseController {
String errorText = "";
ScriptEngine engine = null;
try {
- engine = new NashornJsEngine(script, functionName, argNames);
+ engine = new JsScriptEngine(jsSandboxService, script, functionName, argNames);
TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data, null, null, 0L);
switch (scriptType) {
case "update":
diff --git a/application/src/main/java/org/thingsboard/server/service/executors/AbstractListeningExecutor.java b/application/src/main/java/org/thingsboard/server/service/executors/AbstractListeningExecutor.java
index 91ef9de..210d9da 100644
--- a/application/src/main/java/org/thingsboard/server/service/executors/AbstractListeningExecutor.java
+++ b/application/src/main/java/org/thingsboard/server/service/executors/AbstractListeningExecutor.java
@@ -54,6 +54,10 @@ public abstract class AbstractListeningExecutor implements ListeningExecutor {
service.execute(command);
}
+ public ListeningExecutorService executor() {
+ return service;
+ }
+
protected abstract int getThreadPollSize();
}
diff --git a/application/src/main/java/org/thingsboard/server/service/script/JsSandboxService.java b/application/src/main/java/org/thingsboard/server/service/script/JsSandboxService.java
new file mode 100644
index 0000000..d250857
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/script/JsSandboxService.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.thingsboard.server.service.script;
+
+import javax.script.ScriptException;
+
+public interface JsSandboxService {
+
+ Object eval(String js) throws ScriptException;
+
+ Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException;
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/script/NashornJsSandboxService.java b/application/src/main/java/org/thingsboard/server/service/script/NashornJsSandboxService.java
new file mode 100644
index 0000000..576e149
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/script/NashornJsSandboxService.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.thingsboard.server.service.script;
+
+import delight.nashornsandbox.NashornSandbox;
+import delight.nashornsandbox.NashornSandboxes;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.script.ScriptException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@Slf4j
+@Service
+public class NashornJsSandboxService implements JsSandboxService {
+
+ @Value("${actors.rule.js_sandbox.monitor_thread_pool_size}")
+ private int monitorThreadPoolSize;
+
+ @Value("${actors.rule.js_sandbox.max_cpu_time}")
+ private long maxCpuTime;
+
+ private NashornSandbox sandbox = NashornSandboxes.create();
+ private ExecutorService monitorExecutorService;
+
+ @PostConstruct
+ public void init() {
+ monitorExecutorService = Executors.newFixedThreadPool(monitorThreadPoolSize);
+ sandbox.setExecutor(monitorExecutorService);
+ sandbox.setMaxCPUTime(maxCpuTime);
+ sandbox.allowNoBraces(false);
+ sandbox.setMaxPreparedStatements(30);
+ }
+
+ @PreDestroy
+ public void stop() {
+ if (monitorExecutorService != null) {
+ monitorExecutorService.shutdownNow();
+ }
+ }
+
+ @Override
+ public Object eval(String js) throws ScriptException {
+ return sandbox.eval(js);
+ }
+
+ @Override
+ public Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException {
+ return sandbox.getSandboxedInvocable().invokeFunction(name, args);
+ }
+
+}
diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index 3d50258..50f6e3e 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -238,6 +238,11 @@ actors:
mail_thread_pool_size: "${ACTORS_RULE_MAIL_THREAD_POOL_SIZE:10}"
# Specify thread pool size for external call service
external_call_thread_pool_size: "${ACTORS_RULE_EXTERNAL_CALL_THREAD_POOL_SIZE:10}"
+ js_sandbox:
+ # Specify thread pool size for JavaScript sandbox resource monitor
+ monitor_thread_pool_size: "${ACTORS_RULE_JS_SANDBOX_MONITOR_THREAD_POOL_SIZE:4}"
+ # Maximum CPU time in milliseconds allowed for script execution
+ max_cpu_time: "${ACTORS_RULE_JS_SANDBOX_MAX_CPU_TIME:100}"
chain:
# Errors for particular actor are persisted once per specified amount of milliseconds
error_persist_frequency: "${ACTORS_RULE_CHAIN_ERROR_FREQUENCY:3000}"
diff --git a/application/src/test/java/org/thingsboard/server/service/script/TestNashornJsSandboxService.java b/application/src/test/java/org/thingsboard/server/service/script/TestNashornJsSandboxService.java
new file mode 100644
index 0000000..84cca0c
--- /dev/null
+++ b/application/src/test/java/org/thingsboard/server/service/script/TestNashornJsSandboxService.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.thingsboard.server.service.script;
+
+import delight.nashornsandbox.NashornSandbox;
+import delight.nashornsandbox.NashornSandboxes;
+
+import javax.script.ScriptException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class TestNashornJsSandboxService implements JsSandboxService {
+
+ private NashornSandbox sandbox = NashornSandboxes.create();
+ private ExecutorService monitorExecutorService;
+
+ public TestNashornJsSandboxService(int monitorThreadPoolSize, long maxCpuTime) {
+ monitorExecutorService = Executors.newFixedThreadPool(monitorThreadPoolSize);
+ sandbox.setExecutor(monitorExecutorService);
+ sandbox.setMaxCPUTime(maxCpuTime);
+ sandbox.allowNoBraces(false);
+ sandbox.setMaxPreparedStatements(30);
+ }
+
+ @Override
+ public Object eval(String js) throws ScriptException {
+ return sandbox.eval(js);
+ }
+
+ @Override
+ public Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException {
+ return sandbox.getSandboxedInvocable().invokeFunction(name, args);
+ }
+
+ public void destroy() {
+ if (monitorExecutorService != null) {
+ monitorExecutorService.shutdownNow();
+ }
+ }
+}
pom.xml 6(+6 -0)
diff --git a/pom.xml b/pom.xml
index 97a0271..47d4413 100755
--- a/pom.xml
+++ b/pom.xml
@@ -81,6 +81,7 @@
org/thingsboard/server/extensions/core/plugin/telemetry/gen/**/*
</sonar.exclusions>
<elasticsearch.version>5.0.2</elasticsearch.version>
+ <delight-nashorn-sandbox.version>0.1.14</delight-nashorn-sandbox.version>
</properties>
<modules>
@@ -814,6 +815,11 @@
<artifactId>rest</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.javadelight</groupId>
+ <artifactId>delight-nashorn-sandbox</artifactId>
+ <version>${delight-nashorn-sandbox.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>