thingsboard-memoizeit

Refactor script engine resources.

4/5/2018 9:07:48 AM

Details

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 147c214..b2496c0 100644
--- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
+++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
@@ -29,9 +29,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
-import org.springframework.util.Base64Utils;
 import org.thingsboard.rule.engine.api.ListeningExecutor;
-import org.thingsboard.rule.engine.js.JsExecutorService;
 import org.thingsboard.server.actors.service.ActorService;
 import org.thingsboard.server.common.data.DataConstants;
 import org.thingsboard.server.common.data.Event;
@@ -39,7 +37,6 @@ import org.thingsboard.server.common.data.id.EntityId;
 import org.thingsboard.server.common.data.id.TenantId;
 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
 import org.thingsboard.server.common.msg.TbMsg;
-import org.thingsboard.server.common.msg.TbMsgDataType;
 import org.thingsboard.server.common.msg.cluster.ServerAddress;
 import org.thingsboard.server.common.transport.auth.DeviceAuthService;
 import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint;
@@ -63,15 +60,10 @@ import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
 import org.thingsboard.server.service.component.ComponentDiscoveryService;
 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
 
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.nio.charset.StandardCharsets;
 import java.util.Optional;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 
 @Slf4j
 @Component
@@ -170,6 +162,10 @@ public class ActorSystemContext {
     @Setter
     private PluginWebSocketMsgEndpoint wsMsgEndpoint;
 
+    @Autowired
+    @Getter
+    private ListeningExecutor jsExecutor;
+
     @Value("${actors.session.sync.timeout}")
     @Getter
     private long syncSessionTimeout;
@@ -339,9 +335,4 @@ public class ActorSystemContext {
         return Exception.class.isInstance(error) ? (Exception) error : new Exception(error);
     }
 
-    public ListeningExecutor getJsExecutor() {
-        //TODO: take thread count from yml.
-        return new JsExecutorService(1);
-    }
-
 }
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 03dc376..d3fdc94 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
@@ -20,6 +20,7 @@ import akka.actor.Cancellable;
 import com.google.common.base.Function;
 import org.thingsboard.rule.engine.api.ListeningExecutor;
 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
+import org.thingsboard.rule.engine.api.ScriptEngine;
 import org.thingsboard.rule.engine.api.TbContext;
 import org.thingsboard.server.actors.ActorSystemContext;
 import org.thingsboard.server.common.data.id.RuleNodeId;
@@ -36,6 +37,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 scala.concurrent.duration.Duration;
 
 import java.util.List;
@@ -128,6 +130,11 @@ class DefaultTbContext implements TbContext {
     }
 
     @Override
+    public ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames) {
+        return new NashornJsEngine(script, functionName, argNames);
+    }
+
+    @Override
     public AttributesService getAttributesService() {
         return mainCtx.getAttributesService();
     }
diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index fc04a19..4ffa998 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -219,6 +219,8 @@ actors:
     termination.delay: "${ACTORS_RULE_TERMINATION_DELAY:30000}"
     # Errors for particular actor are persisted once per specified amount of milliseconds
     error_persist_frequency: "${ACTORS_RULE_ERROR_FREQUENCY:3000}"
+    # Specify thread pool size for javascript executor service
+    js_thread_pool_size: "${ACTORS_RULE_JS_THREAD_POOL_SIZE:10}"
     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/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ListeningExecutor.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ListeningExecutor.java
index fecf019..5420f7f 100644
--- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ListeningExecutor.java
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ListeningExecutor.java
@@ -23,5 +23,4 @@ public interface ListeningExecutor {
 
     <T> ListenableFuture<T> executeAsync(Callable<T> task);
 
-    void onDestroy();
 }
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ScriptEngine.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ScriptEngine.java
new file mode 100644
index 0000000..c2c8210
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ScriptEngine.java
@@ -0,0 +1,35 @@
+/**
+ * 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.rule.engine.api;
+
+import org.thingsboard.server.common.msg.TbMsg;
+
+import javax.script.ScriptException;
+import java.util.Set;
+
+public interface ScriptEngine {
+
+    TbMsg executeUpdate(TbMsg msg) throws ScriptException;
+
+    TbMsg executeGenerate(TbMsg prevMsg) throws ScriptException;
+
+    boolean executeFilter(TbMsg msg) throws ScriptException;
+
+    Set<String> executeSwitch(TbMsg msg) throws ScriptException;
+
+    void destroy();
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
index 9b63041..b8c2b38 100644
--- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
@@ -83,4 +83,6 @@ public interface TbContext {
 
     ListeningExecutor getJsExecutor();
 
+    ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames);
+
 }
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java
index 857baf6..65b1371 100644
--- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java
@@ -20,23 +20,13 @@ import com.google.common.util.concurrent.ListenableFuture;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.util.StringUtils;
 import org.thingsboard.rule.engine.TbNodeUtils;
-import org.thingsboard.rule.engine.api.ListeningExecutor;
-import org.thingsboard.rule.engine.api.RuleNode;
-import org.thingsboard.rule.engine.api.TbContext;
-import org.thingsboard.rule.engine.api.TbNode;
-import org.thingsboard.rule.engine.api.TbNodeConfiguration;
-import org.thingsboard.rule.engine.api.TbNodeException;
-import org.thingsboard.rule.engine.filter.TbJsFilterNodeConfiguration;
-import org.thingsboard.rule.engine.js.NashornJsEngine;
+import org.thingsboard.rule.engine.api.*;
 import org.thingsboard.server.common.data.id.EntityId;
 import org.thingsboard.server.common.data.id.EntityIdFactory;
 import org.thingsboard.server.common.data.plugin.ComponentType;
 import org.thingsboard.server.common.msg.TbMsg;
 import org.thingsboard.server.common.msg.TbMsgMetaData;
 
-import javax.script.Bindings;
-
-import java.nio.charset.StandardCharsets;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
@@ -59,7 +49,7 @@ public class TbMsgGeneratorNode implements TbNode {
     public static final String TB_MSG_GENERATOR_NODE_MSG = "TbMsgGeneratorNodeMsg";
 
     private TbMsgGeneratorNodeConfiguration config;
-    private NashornJsEngine jsEngine;
+    private ScriptEngine jsEngine;
     private long delay;
     private EntityId originatorId;
     private UUID nextTickId;
@@ -74,7 +64,7 @@ public class TbMsgGeneratorNode implements TbNode {
         } else {
             originatorId = ctx.getSelfId();
         }
-        this.jsEngine = new NashornJsEngine(config.getJsScript(), "Generate", "prevMsg", "prevMetadata", "prevMsgType");
+        this.jsEngine = ctx.createJsScriptEngine(config.getJsScript(), "Generate", "prevMsg", "prevMetadata", "prevMsgType");
         sentTickMsg(ctx);
     }
 
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java
index f08135b..8ad344f 100644
--- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java
@@ -18,12 +18,9 @@ package org.thingsboard.rule.engine.filter;
 import lombok.extern.slf4j.Slf4j;
 import org.thingsboard.rule.engine.TbNodeUtils;
 import org.thingsboard.rule.engine.api.*;
-import org.thingsboard.rule.engine.js.NashornJsEngine;
 import org.thingsboard.server.common.data.plugin.ComponentType;
 import org.thingsboard.server.common.msg.TbMsg;
 
-import javax.script.Bindings;
-
 import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
 
 @Slf4j
@@ -43,12 +40,12 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
 public class TbJsFilterNode implements TbNode {
 
     private TbJsFilterNodeConfiguration config;
-    private NashornJsEngine jsEngine;
+    private ScriptEngine jsEngine;
 
     @Override
     public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
         this.config = TbNodeUtils.convert(configuration, TbJsFilterNodeConfiguration.class);
-        this.jsEngine = new NashornJsEngine(config.getJsScript(), "Filter");
+        this.jsEngine = ctx.createJsScriptEngine(config.getJsScript(), "Filter");
     }
 
     @Override
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java
index 0a96fab..3c6704b 100644
--- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java
@@ -18,11 +18,9 @@ package org.thingsboard.rule.engine.filter;
 import lombok.extern.slf4j.Slf4j;
 import org.thingsboard.rule.engine.TbNodeUtils;
 import org.thingsboard.rule.engine.api.*;
-import org.thingsboard.rule.engine.js.NashornJsEngine;
 import org.thingsboard.server.common.data.plugin.ComponentType;
 import org.thingsboard.server.common.msg.TbMsg;
 
-import javax.script.Bindings;
 import java.util.Set;
 
 import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
@@ -43,12 +41,12 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
 public class TbJsSwitchNode implements TbNode {
 
     private TbJsSwitchNodeConfiguration config;
-    private NashornJsEngine jsEngine;
+    private ScriptEngine jsEngine;
 
     @Override
     public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
         this.config = TbNodeUtils.convert(configuration, TbJsSwitchNodeConfiguration.class);
-        this.jsEngine = new NashornJsEngine(config.getJsScript(), "Switch");
+        this.jsEngine = ctx.createJsScriptEngine(config.getJsScript(), "Switch");
     }
 
     @Override
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java
index bbb4b5f..bf0c9fe 100644
--- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java
@@ -18,12 +18,9 @@ package org.thingsboard.rule.engine.transform;
 import com.google.common.util.concurrent.ListenableFuture;
 import org.thingsboard.rule.engine.TbNodeUtils;
 import org.thingsboard.rule.engine.api.*;
-import org.thingsboard.rule.engine.js.NashornJsEngine;
 import org.thingsboard.server.common.data.plugin.ComponentType;
 import org.thingsboard.server.common.msg.TbMsg;
 
-import javax.script.Bindings;
-
 @RuleNode(
         type = ComponentType.TRANSFORMATION,
         name = "script",
@@ -41,12 +38,12 @@ import javax.script.Bindings;
 public class TbTransformMsgNode extends TbAbstractTransformNode {
 
     private TbTransformMsgNodeConfiguration config;
-    private NashornJsEngine jsEngine;
+    private ScriptEngine jsEngine;
 
     @Override
     public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
         this.config = TbNodeUtils.convert(configuration, TbTransformMsgNodeConfiguration.class);
-        this.jsEngine = new NashornJsEngine(config.getJsScript(), "Transform");
+        this.jsEngine = ctx.createJsScriptEngine(config.getJsScript(), "Transform");
         setConfig(config);
     }
 
diff --git a/ui/src/app/rulechain/rulechain.controller.js b/ui/src/app/rulechain/rulechain.controller.js
index c20fa44..9bd7960 100644
--- a/ui/src/app/rulechain/rulechain.controller.js
+++ b/ui/src/app/rulechain/rulechain.controller.js
@@ -353,7 +353,9 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
                 vm.editingRuleNodeLinkIndex = vm.ruleChainModel.edges.indexOf(edge);
                 vm.editingRuleNodeLink = angular.copy(edge);
                 $mdUtil.nextTick(() => {
-                    vm.ruleNodeLinkForm.$setPristine();
+                    if (vm.ruleNodeLinkForm) {
+                        vm.ruleNodeLinkForm.$setPristine();
+                    }
                 });
             }
         },
@@ -366,7 +368,9 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
                     vm.editingRuleNodeIndex = vm.ruleChainModel.nodes.indexOf(node);
                     vm.editingRuleNode = angular.copy(node);
                     $mdUtil.nextTick(() => {
-                        vm.ruleNodeForm.$setPristine();
+                        if (vm.ruleNodeForm) {
+                            vm.ruleNodeForm.$setPristine();
+                        }
                     });
                 }
             }
@@ -737,7 +741,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
                         nodes.push(node);
                     }
                 }
-                var res = $filter('filter')(vm.ruleChainModel.edges, {source: vm.inputConnectorId});
+                var res = $filter('filter')(vm.ruleChainModel.edges, {source: vm.inputConnectorId}, true);
                 if (res && res.length) {
                     var firstNodeEdge = res[0];
                     var firstNode = vm.modelservice.nodes.getNodeByConnectorId(firstNodeEdge.destination);