diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index 18e35c6744..6bb3917652 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -247,7 +247,7 @@ spring:
database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.HSQLDialect}"
datasource:
driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.hsqldb.jdbc.JDBCDriver}"
- url: "${SPRING_DATASOURCE_URL:jdbc:hsqldb:file:${SQL_DATA_FOLDER:/tmp}/thingsboardDb;sql.enforce_size=false}"
+ url: "${SPRING_DATASOURCE_URL:jdbc:hsqldb:file:${SQL_DATA_FOLDER:/tmp}/thingsboardDb;sql.enforce_size=false;hsqldb.log_size=5}"
username: "${SPRING_DATASOURCE_USERNAME:sa}"
password: "${SPRING_DATASOURCE_PASSWORD:}"
diff --git a/dao/pom.xml b/dao/pom.xml
index d9463e4f9c..8d43822342 100644
--- a/dao/pom.xml
+++ b/dao/pom.xml
@@ -23,7 +23,6 @@
1.4.0-SNAPSHOT
thingsboard
- org.thingsboard
dao
jar
diff --git a/pom.xml b/pom.xml
index 4b77abbd98..27e5216897 100755
--- a/pom.xml
+++ b/pom.xml
@@ -85,6 +85,7 @@
extensions-api
extensions-core
extensions
+ rule-engine
transport
ui
tools
diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml
new file mode 100644
index 0000000000..e23f8714e3
--- /dev/null
+++ b/rule-engine/pom.xml
@@ -0,0 +1,42 @@
+
+
+ 4.0.0
+
+ org.thingsboard
+ 1.4.0-SNAPSHOT
+ thingsboard
+
+ org.thingsboard
+ rule-engine
+ pom
+
+ Thingsboard Extensions
+ https://thingsboard.io
+
+
+ ${basedir}/..
+
+
+
+ rule-engine-api
+ rule-engine-components
+
+
+
diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml
new file mode 100644
index 0000000000..69cbc65965
--- /dev/null
+++ b/rule-engine/rule-engine-api/pom.xml
@@ -0,0 +1,67 @@
+
+
+
+ 4.0.0
+
+ org.thingsboard
+ 1.4.0-SNAPSHOT
+ rule-engine
+
+ org.thingsboard.rule-engine
+ rule-engine-api
+ jar
+
+ Thingsboard Rule Engine API
+ https://thingsboard.io
+
+
+ UTF-8
+ ${basedir}/../..
+
+
+
+
+ org.thingsboard.common
+ message
+ provided
+
+
+ org.thingsboard
+ extensions-api
+ provided
+
+
+ org.thingsboard
+ dao
+ provided
+
+
+ ch.qos.logback
+ logback-core
+ provided
+
+
+ ch.qos.logback
+ logback-classic
+ provided
+
+
+
\ No newline at end of file
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
new file mode 100644
index 0000000000..b833a97759
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
@@ -0,0 +1,29 @@
+package org.thingsboard.rule.engine.api;
+
+import org.thingsboard.server.common.msg.cluster.ServerAddress;
+import org.thingsboard.server.dao.attributes.AttributesService;
+
+import java.util.UUID;
+
+/**
+ * Created by ashvayka on 13.01.18.
+ */
+public interface TbContext {
+
+ void tellNext(TbMsg msg);
+
+ void tellNext(TbMsg msg, String relationType);
+
+ void tellSelf(TbMsg msg, long delayMs);
+
+ void tellOthers(TbMsg msg);
+
+ void tellSibling(TbMsg msg, ServerAddress address);
+
+ void spawn(TbMsg msg);
+
+ void ack(UUID msg);
+
+ AttributesService getAttributesService();
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsg.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsg.java
new file mode 100644
index 0000000000..9917c6a505
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsg.java
@@ -0,0 +1,22 @@
+package org.thingsboard.rule.engine.api;
+
+import lombok.Data;
+import org.thingsboard.server.common.data.id.EntityId;
+
+import java.io.Serializable;
+import java.util.UUID;
+
+/**
+ * Created by ashvayka on 13.01.18.
+ */
+@Data
+public final class TbMsg implements Serializable {
+
+ private final UUID id;
+ private final String type;
+ private final EntityId originator;
+ private final TbMsgMetaData metaData;
+
+ private final byte[] data;
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsgMetaData.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsgMetaData.java
new file mode 100644
index 0000000000..56abf2a12d
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsgMetaData.java
@@ -0,0 +1,24 @@
+package org.thingsboard.rule.engine.api;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * Created by ashvayka on 13.01.18.
+ */
+@Data
+public final class TbMsgMetaData implements Serializable {
+
+ private Map data;
+
+ public String getValue(String key) {
+ return data.get(key);
+ }
+
+ public void putValue(String key, String value) {
+ data.put(key, value);
+ }
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java
new file mode 100644
index 0000000000..70993df47a
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java
@@ -0,0 +1,16 @@
+package org.thingsboard.rule.engine.api;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+public interface TbNode {
+
+ void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException;
+
+ void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException;
+
+ void destroy();
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeConfiguration.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeConfiguration.java
new file mode 100644
index 0000000000..4ab84aaeed
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeConfiguration.java
@@ -0,0 +1,14 @@
+package org.thingsboard.rule.engine.api;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.Data;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Data
+public class TbNodeConfiguration {
+
+ private JsonNode data;
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeException.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeException.java
new file mode 100644
index 0000000000..5a3744b08c
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeException.java
@@ -0,0 +1,14 @@
+package org.thingsboard.rule.engine.api;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+public class TbNodeException extends Exception {
+
+ public TbNodeException(Exception e) {
+ super(e);
+ }
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeState.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeState.java
new file mode 100644
index 0000000000..15f4c30774
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeState.java
@@ -0,0 +1,7 @@
+package org.thingsboard.rule.engine.api;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+public class TbNodeState {
+}
diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml
new file mode 100644
index 0000000000..ee0d83f9a7
--- /dev/null
+++ b/rule-engine/rule-engine-components/pom.xml
@@ -0,0 +1,67 @@
+
+
+
+ 4.0.0
+
+ org.thingsboard
+ 1.4.0-SNAPSHOT
+ rule-engine
+
+ org.thingsboard.rule-engine
+ rule-engine-components
+ jar
+
+ Thingsboard Rule Engine Components
+ https://thingsboard.io
+
+
+ UTF-8
+ ${basedir}/../..
+
+
+
+
+ org.thingsboard
+ dao
+ provided
+
+
+ ch.qos.logback
+ logback-core
+ provided
+
+
+ ch.qos.logback
+ logback-classic
+ provided
+
+
+ org.thingsboard
+ extensions-api
+ provided
+
+
+ org.thingsboard.rule-engine
+ rule-engine-api
+ 1.4.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/TbNodeUtils.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/TbNodeUtils.java
new file mode 100644
index 0000000000..962ea10c9c
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/TbNodeUtils.java
@@ -0,0 +1,23 @@
+package org.thingsboard.rule.engine;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.thingsboard.rule.engine.api.TbNodeConfiguration;
+import org.thingsboard.rule.engine.api.TbNodeException;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+public class TbNodeUtils {
+
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ public static T convert(TbNodeConfiguration configuration, Class clazz) throws TbNodeException {
+ try {
+ return mapper.treeToValue(configuration.getData(), clazz);
+ } catch (JsonProcessingException e) {
+ throw new TbNodeException(e);
+ }
+ }
+
+}
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java
new file mode 100644
index 0000000000..034ee48e58
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java
@@ -0,0 +1,35 @@
+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.metadata.TbGetAttributesNodeConfiguration;
+import org.thingsboard.server.common.data.DataConstants;
+import org.thingsboard.server.common.data.kv.AttributeKvEntry;
+import org.thingsboard.server.dao.attributes.AttributesService;
+
+import java.util.List;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Slf4j
+public class TbMsgTypeFilterNode implements TbNode {
+
+ TbMsgTypeFilterNodeConfiguration config;
+
+ @Override
+ public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException {
+ this.config = TbNodeUtils.convert(configuration, TbMsgTypeFilterNodeConfiguration.class);
+ }
+
+ @Override
+ public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
+ ctx.tellNext(msg, Boolean.toString(config.getMessageTypes().contains(msg.getType())));
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+}
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java
new file mode 100644
index 0000000000..e7662070c4
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java
@@ -0,0 +1,15 @@
+package org.thingsboard.rule.engine.filter;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Data
+public class TbMsgTypeFilterNodeConfiguration {
+
+ private List messageTypes;
+
+}
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java
new file mode 100644
index 0000000000..b623af7609
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java
@@ -0,0 +1,51 @@
+package org.thingsboard.rule.engine.metadata;
+
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.rule.engine.TbNodeUtils;
+import org.thingsboard.rule.engine.api.*;
+import org.thingsboard.server.common.data.DataConstants;
+import org.thingsboard.server.common.data.kv.AttributeKvEntry;
+import org.thingsboard.server.dao.attributes.AttributesService;
+
+import java.util.List;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Slf4j
+public class TbGetAttributesNode implements TbNode {
+
+ TbGetAttributesNodeConfiguration config;
+
+ @Override
+ public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException {
+ this.config = TbNodeUtils.convert(configuration, TbGetAttributesNodeConfiguration.class);
+ }
+
+ @Override
+ public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
+ try {
+ //TODO: refactor this to work async and fetch attributes from cache.
+ AttributesService service = ctx.getAttributesService();
+ fetchAttributes(msg, service, config.getClientAttributeNames(), DataConstants.CLIENT_SCOPE, "cs.");
+ fetchAttributes(msg, service, config.getServerAttributeNames(), DataConstants.SERVER_SCOPE, "ss.");
+ fetchAttributes(msg, service, config.getSharedAttributeNames(), DataConstants.SHARED_SCOPE, "shared.");
+ ctx.tellNext(msg);
+ } catch (Exception e) {
+ log.warn("[{}][{}] Failed to fetch attributes", msg.getOriginator(), msg.getId(), e);
+ throw new TbNodeException(e);
+ }
+ }
+
+ private void fetchAttributes(TbMsg msg, AttributesService service, List attributeNames, String scope, String prefix) throws InterruptedException, java.util.concurrent.ExecutionException {
+ if (attributeNames != null && attributeNames.isEmpty()) {
+ List attributes = service.find(msg.getOriginator(), scope, attributeNames).get();
+ attributes.forEach(attr -> msg.getMetaData().putValue(prefix + attr.getKey(), attr.getValueAsString()));
+ }
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+}
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java
new file mode 100644
index 0000000000..076500c7ec
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java
@@ -0,0 +1,17 @@
+package org.thingsboard.rule.engine.metadata;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Data
+public class TbGetAttributesNodeConfiguration {
+
+ private List clientAttributeNames;
+ private List sharedAttributeNames;
+ private List serverAttributeNames;
+
+}
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformNode.java
new file mode 100644
index 0000000000..837f33342f
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformNode.java
@@ -0,0 +1,52 @@
+package org.thingsboard.rule.engine.transform;
+
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.rule.engine.TbNodeUtils;
+import org.thingsboard.rule.engine.api.*;
+import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
+import org.thingsboard.server.common.data.DataConstants;
+import org.thingsboard.server.common.data.kv.AttributeKvEntry;
+import org.thingsboard.server.dao.attributes.AttributesService;
+
+import java.util.List;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Slf4j
+public class TbTransformNode implements TbNode {
+
+ TbGetAttributesNodeConfiguration config;
+
+ @Override
+ public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException {
+ this.config = TbNodeUtils.convert(configuration, TbGetAttributesNodeConfiguration.class);
+ }
+
+ @Override
+ public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
+ try {
+ //TODO: refactor this to work async and fetch attributes from cache.
+ AttributesService service = ctx.getAttributesService();
+ fetchAttributes(msg, service, config.getClientAttributeNames(), DataConstants.CLIENT_SCOPE, "cs.");
+ fetchAttributes(msg, service, config.getServerAttributeNames(), DataConstants.SERVER_SCOPE, "ss.");
+ fetchAttributes(msg, service, config.getSharedAttributeNames(), DataConstants.SHARED_SCOPE, "shared.");
+ ctx.tellNext(msg);
+ } catch (Exception e) {
+ log.warn("[{}][{}] Failed to fetch attributes", msg.getOriginator(), msg.getId(), e);
+ throw new TbNodeException(e);
+ }
+ }
+
+ private void fetchAttributes(TbMsg msg, AttributesService service, List attributeNames, String scope, String prefix) throws InterruptedException, java.util.concurrent.ExecutionException {
+ if (attributeNames != null && attributeNames.isEmpty()) {
+ List attributes = service.find(msg.getOriginator(), scope, attributeNames).get();
+ attributes.forEach(attr -> msg.getMetaData().putValue(prefix + attr.getKey(), attr.getValueAsString()));
+ }
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+}