Commit f1a4c683f235d453d7ebe8654e23aa59bc5b967c

Authored by Andrew Shvayka
1 parent cf7e5861

Rule Engine draft

Showing 19 changed files with 497 additions and 2 deletions
... ... @@ -247,7 +247,7 @@ spring:
247 247 database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.HSQLDialect}"
248 248 datasource:
249 249 driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.hsqldb.jdbc.JDBCDriver}"
250   - url: "${SPRING_DATASOURCE_URL:jdbc:hsqldb:file:${SQL_DATA_FOLDER:/tmp}/thingsboardDb;sql.enforce_size=false}"
  250 + url: "${SPRING_DATASOURCE_URL:jdbc:hsqldb:file:${SQL_DATA_FOLDER:/tmp}/thingsboardDb;sql.enforce_size=false;hsqldb.log_size=5}"
251 251 username: "${SPRING_DATASOURCE_USERNAME:sa}"
252 252 password: "${SPRING_DATASOURCE_PASSWORD:}"
253 253
... ...
... ... @@ -23,7 +23,6 @@
23 23 <version>1.4.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26   - <groupId>org.thingsboard</groupId>
27 26 <artifactId>dao</artifactId>
28 27 <packaging>jar</packaging>
29 28
... ...
... ... @@ -85,6 +85,7 @@
85 85 <module>extensions-api</module>
86 86 <module>extensions-core</module>
87 87 <module>extensions</module>
  88 + <module>rule-engine</module>
88 89 <module>transport</module>
89 90 <module>ui</module>
90 91 <module>tools</module>
... ...
  1 +<!--
  2 +
  3 + Copyright © 2016-2017 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  20 + <modelVersion>4.0.0</modelVersion>
  21 + <parent>
  22 + <groupId>org.thingsboard</groupId>
  23 + <version>1.4.0-SNAPSHOT</version>
  24 + <artifactId>thingsboard</artifactId>
  25 + </parent>
  26 + <groupId>org.thingsboard</groupId>
  27 + <artifactId>rule-engine</artifactId>
  28 + <packaging>pom</packaging>
  29 +
  30 + <name>Thingsboard Extensions</name>
  31 + <url>https://thingsboard.io</url>
  32 +
  33 + <properties>
  34 + <main.dir>${basedir}/..</main.dir>
  35 + </properties>
  36 +
  37 + <modules>
  38 + <module>rule-engine-api</module>
  39 + <module>rule-engine-components</module>
  40 + </modules>
  41 +
  42 +</project>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!--
  3 +
  4 + Copyright © 2016-2017 The Thingsboard Authors
  5 +
  6 + Licensed under the Apache License, Version 2.0 (the "License");
  7 + you may not use this file except in compliance with the License.
  8 + You may obtain a copy of the License at
  9 +
  10 + http://www.apache.org/licenses/LICENSE-2.0
  11 +
  12 + Unless required by applicable law or agreed to in writing, software
  13 + distributed under the License is distributed on an "AS IS" BASIS,
  14 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + See the License for the specific language governing permissions and
  16 + limitations under the License.
  17 +
  18 +-->
  19 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  20 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  21 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  22 + <modelVersion>4.0.0</modelVersion>
  23 + <parent>
  24 + <groupId>org.thingsboard</groupId>
  25 + <version>1.4.0-SNAPSHOT</version>
  26 + <artifactId>rule-engine</artifactId>
  27 + </parent>
  28 + <groupId>org.thingsboard.rule-engine</groupId>
  29 + <artifactId>rule-engine-api</artifactId>
  30 + <packaging>jar</packaging>
  31 +
  32 + <name>Thingsboard Rule Engine API</name>
  33 + <url>https://thingsboard.io</url>
  34 +
  35 + <properties>
  36 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  37 + <main.dir>${basedir}/../..</main.dir>
  38 + </properties>
  39 +
  40 + <dependencies>
  41 + <dependency>
  42 + <groupId>org.thingsboard.common</groupId>
  43 + <artifactId>message</artifactId>
  44 + <scope>provided</scope>
  45 + </dependency>
  46 + <dependency>
  47 + <groupId>org.thingsboard</groupId>
  48 + <artifactId>extensions-api</artifactId>
  49 + <scope>provided</scope>
  50 + </dependency>
  51 + <dependency>
  52 + <groupId>org.thingsboard</groupId>
  53 + <artifactId>dao</artifactId>
  54 + <scope>provided</scope>
  55 + </dependency>
  56 + <dependency>
  57 + <groupId>ch.qos.logback</groupId>
  58 + <artifactId>logback-core</artifactId>
  59 + <scope>provided</scope>
  60 + </dependency>
  61 + <dependency>
  62 + <groupId>ch.qos.logback</groupId>
  63 + <artifactId>logback-classic</artifactId>
  64 + <scope>provided</scope>
  65 + </dependency>
  66 + </dependencies>
  67 +</project>
\ No newline at end of file
... ...
  1 +package org.thingsboard.rule.engine.api;
  2 +
  3 +import org.thingsboard.server.common.msg.cluster.ServerAddress;
  4 +import org.thingsboard.server.dao.attributes.AttributesService;
  5 +
  6 +import java.util.UUID;
  7 +
  8 +/**
  9 + * Created by ashvayka on 13.01.18.
  10 + */
  11 +public interface TbContext {
  12 +
  13 + void tellNext(TbMsg msg);
  14 +
  15 + void tellNext(TbMsg msg, String relationType);
  16 +
  17 + void tellSelf(TbMsg msg, long delayMs);
  18 +
  19 + void tellOthers(TbMsg msg);
  20 +
  21 + void tellSibling(TbMsg msg, ServerAddress address);
  22 +
  23 + void spawn(TbMsg msg);
  24 +
  25 + void ack(UUID msg);
  26 +
  27 + AttributesService getAttributesService();
  28 +
  29 +}
... ...
  1 +package org.thingsboard.rule.engine.api;
  2 +
  3 +import lombok.Data;
  4 +import org.thingsboard.server.common.data.id.EntityId;
  5 +
  6 +import java.io.Serializable;
  7 +import java.util.UUID;
  8 +
  9 +/**
  10 + * Created by ashvayka on 13.01.18.
  11 + */
  12 +@Data
  13 +public final class TbMsg implements Serializable {
  14 +
  15 + private final UUID id;
  16 + private final String type;
  17 + private final EntityId originator;
  18 + private final TbMsgMetaData metaData;
  19 +
  20 + private final byte[] data;
  21 +
  22 +}
... ...
  1 +package org.thingsboard.rule.engine.api;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.io.Serializable;
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * Created by ashvayka on 13.01.18.
  10 + */
  11 +@Data
  12 +public final class TbMsgMetaData implements Serializable {
  13 +
  14 + private Map<String, String> data;
  15 +
  16 + public String getValue(String key) {
  17 + return data.get(key);
  18 + }
  19 +
  20 + public void putValue(String key, String value) {
  21 + data.put(key, value);
  22 + }
  23 +
  24 +}
... ...
  1 +package org.thingsboard.rule.engine.api;
  2 +
  3 +import java.util.concurrent.ExecutionException;
  4 +
  5 +/**
  6 + * Created by ashvayka on 19.01.18.
  7 + */
  8 +public interface TbNode {
  9 +
  10 + void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException;
  11 +
  12 + void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException;
  13 +
  14 + void destroy();
  15 +
  16 +}
... ...
  1 +package org.thingsboard.rule.engine.api;
  2 +
  3 +import com.fasterxml.jackson.databind.JsonNode;
  4 +import lombok.Data;
  5 +
  6 +/**
  7 + * Created by ashvayka on 19.01.18.
  8 + */
  9 +@Data
  10 +public class TbNodeConfiguration {
  11 +
  12 + private JsonNode data;
  13 +
  14 +}
... ...
  1 +package org.thingsboard.rule.engine.api;
  2 +
  3 +import com.fasterxml.jackson.core.JsonProcessingException;
  4 +
  5 +/**
  6 + * Created by ashvayka on 19.01.18.
  7 + */
  8 +public class TbNodeException extends Exception {
  9 +
  10 + public TbNodeException(Exception e) {
  11 + super(e);
  12 + }
  13 +
  14 +}
... ...
  1 +package org.thingsboard.rule.engine.api;
  2 +
  3 +/**
  4 + * Created by ashvayka on 19.01.18.
  5 + */
  6 +public class TbNodeState {
  7 +}
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!--
  3 +
  4 + Copyright © 2016-2017 The Thingsboard Authors
  5 +
  6 + Licensed under the Apache License, Version 2.0 (the "License");
  7 + you may not use this file except in compliance with the License.
  8 + You may obtain a copy of the License at
  9 +
  10 + http://www.apache.org/licenses/LICENSE-2.0
  11 +
  12 + Unless required by applicable law or agreed to in writing, software
  13 + distributed under the License is distributed on an "AS IS" BASIS,
  14 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + See the License for the specific language governing permissions and
  16 + limitations under the License.
  17 +
  18 +-->
  19 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  20 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  21 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  22 + <modelVersion>4.0.0</modelVersion>
  23 + <parent>
  24 + <groupId>org.thingsboard</groupId>
  25 + <version>1.4.0-SNAPSHOT</version>
  26 + <artifactId>rule-engine</artifactId>
  27 + </parent>
  28 + <groupId>org.thingsboard.rule-engine</groupId>
  29 + <artifactId>rule-engine-components</artifactId>
  30 + <packaging>jar</packaging>
  31 +
  32 + <name>Thingsboard Rule Engine Components</name>
  33 + <url>https://thingsboard.io</url>
  34 +
  35 + <properties>
  36 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  37 + <main.dir>${basedir}/../..</main.dir>
  38 + </properties>
  39 +
  40 + <dependencies>
  41 + <dependency>
  42 + <groupId>org.thingsboard</groupId>
  43 + <artifactId>dao</artifactId>
  44 + <scope>provided</scope>
  45 + </dependency>
  46 + <dependency>
  47 + <groupId>ch.qos.logback</groupId>
  48 + <artifactId>logback-core</artifactId>
  49 + <scope>provided</scope>
  50 + </dependency>
  51 + <dependency>
  52 + <groupId>ch.qos.logback</groupId>
  53 + <artifactId>logback-classic</artifactId>
  54 + <scope>provided</scope>
  55 + </dependency>
  56 + <dependency>
  57 + <groupId>org.thingsboard</groupId>
  58 + <artifactId>extensions-api</artifactId>
  59 + <scope>provided</scope>
  60 + </dependency>
  61 + <dependency>
  62 + <groupId>org.thingsboard.rule-engine</groupId>
  63 + <artifactId>rule-engine-api</artifactId>
  64 + <version>1.4.0-SNAPSHOT</version>
  65 + </dependency>
  66 + </dependencies>
  67 +</project>
\ No newline at end of file
... ...
  1 +package org.thingsboard.rule.engine;
  2 +
  3 +import com.fasterxml.jackson.core.JsonProcessingException;
  4 +import com.fasterxml.jackson.databind.ObjectMapper;
  5 +import org.thingsboard.rule.engine.api.TbNodeConfiguration;
  6 +import org.thingsboard.rule.engine.api.TbNodeException;
  7 +
  8 +/**
  9 + * Created by ashvayka on 19.01.18.
  10 + */
  11 +public class TbNodeUtils {
  12 +
  13 + private static final ObjectMapper mapper = new ObjectMapper();
  14 +
  15 + public static <T> T convert(TbNodeConfiguration configuration, Class<T> clazz) throws TbNodeException {
  16 + try {
  17 + return mapper.treeToValue(configuration.getData(), clazz);
  18 + } catch (JsonProcessingException e) {
  19 + throw new TbNodeException(e);
  20 + }
  21 + }
  22 +
  23 +}
... ...
  1 +package org.thingsboard.rule.engine.filter;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.thingsboard.rule.engine.TbNodeUtils;
  5 +import org.thingsboard.rule.engine.api.*;
  6 +import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
  7 +import org.thingsboard.server.common.data.DataConstants;
  8 +import org.thingsboard.server.common.data.kv.AttributeKvEntry;
  9 +import org.thingsboard.server.dao.attributes.AttributesService;
  10 +
  11 +import java.util.List;
  12 +
  13 +/**
  14 + * Created by ashvayka on 19.01.18.
  15 + */
  16 +@Slf4j
  17 +public class TbMsgTypeFilterNode implements TbNode {
  18 +
  19 + TbMsgTypeFilterNodeConfiguration config;
  20 +
  21 + @Override
  22 + public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException {
  23 + this.config = TbNodeUtils.convert(configuration, TbMsgTypeFilterNodeConfiguration.class);
  24 + }
  25 +
  26 + @Override
  27 + public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
  28 + ctx.tellNext(msg, Boolean.toString(config.getMessageTypes().contains(msg.getType())));
  29 + }
  30 +
  31 + @Override
  32 + public void destroy() {
  33 +
  34 + }
  35 +}
... ...
  1 +package org.thingsboard.rule.engine.filter;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * Created by ashvayka on 19.01.18.
  9 + */
  10 +@Data
  11 +public class TbMsgTypeFilterNodeConfiguration {
  12 +
  13 + private List<String> messageTypes;
  14 +
  15 +}
... ...
  1 +package org.thingsboard.rule.engine.metadata;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.thingsboard.rule.engine.TbNodeUtils;
  5 +import org.thingsboard.rule.engine.api.*;
  6 +import org.thingsboard.server.common.data.DataConstants;
  7 +import org.thingsboard.server.common.data.kv.AttributeKvEntry;
  8 +import org.thingsboard.server.dao.attributes.AttributesService;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * Created by ashvayka on 19.01.18.
  14 + */
  15 +@Slf4j
  16 +public class TbGetAttributesNode implements TbNode {
  17 +
  18 + TbGetAttributesNodeConfiguration config;
  19 +
  20 + @Override
  21 + public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException {
  22 + this.config = TbNodeUtils.convert(configuration, TbGetAttributesNodeConfiguration.class);
  23 + }
  24 +
  25 + @Override
  26 + public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
  27 + try {
  28 + //TODO: refactor this to work async and fetch attributes from cache.
  29 + AttributesService service = ctx.getAttributesService();
  30 + fetchAttributes(msg, service, config.getClientAttributeNames(), DataConstants.CLIENT_SCOPE, "cs.");
  31 + fetchAttributes(msg, service, config.getServerAttributeNames(), DataConstants.SERVER_SCOPE, "ss.");
  32 + fetchAttributes(msg, service, config.getSharedAttributeNames(), DataConstants.SHARED_SCOPE, "shared.");
  33 + ctx.tellNext(msg);
  34 + } catch (Exception e) {
  35 + log.warn("[{}][{}] Failed to fetch attributes", msg.getOriginator(), msg.getId(), e);
  36 + throw new TbNodeException(e);
  37 + }
  38 + }
  39 +
  40 + private void fetchAttributes(TbMsg msg, AttributesService service, List<String> attributeNames, String scope, String prefix) throws InterruptedException, java.util.concurrent.ExecutionException {
  41 + if (attributeNames != null && attributeNames.isEmpty()) {
  42 + List<AttributeKvEntry> attributes = service.find(msg.getOriginator(), scope, attributeNames).get();
  43 + attributes.forEach(attr -> msg.getMetaData().putValue(prefix + attr.getKey(), attr.getValueAsString()));
  44 + }
  45 + }
  46 +
  47 + @Override
  48 + public void destroy() {
  49 +
  50 + }
  51 +}
... ...
  1 +package org.thingsboard.rule.engine.metadata;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * Created by ashvayka on 19.01.18.
  9 + */
  10 +@Data
  11 +public class TbGetAttributesNodeConfiguration {
  12 +
  13 + private List<String> clientAttributeNames;
  14 + private List<String> sharedAttributeNames;
  15 + private List<String> serverAttributeNames;
  16 +
  17 +}
... ...
  1 +package org.thingsboard.rule.engine.transform;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.thingsboard.rule.engine.TbNodeUtils;
  5 +import org.thingsboard.rule.engine.api.*;
  6 +import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
  7 +import org.thingsboard.server.common.data.DataConstants;
  8 +import org.thingsboard.server.common.data.kv.AttributeKvEntry;
  9 +import org.thingsboard.server.dao.attributes.AttributesService;
  10 +
  11 +import java.util.List;
  12 +
  13 +/**
  14 + * Created by ashvayka on 19.01.18.
  15 + */
  16 +@Slf4j
  17 +public class TbTransformNode implements TbNode {
  18 +
  19 + TbGetAttributesNodeConfiguration config;
  20 +
  21 + @Override
  22 + public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException {
  23 + this.config = TbNodeUtils.convert(configuration, TbGetAttributesNodeConfiguration.class);
  24 + }
  25 +
  26 + @Override
  27 + public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
  28 + try {
  29 + //TODO: refactor this to work async and fetch attributes from cache.
  30 + AttributesService service = ctx.getAttributesService();
  31 + fetchAttributes(msg, service, config.getClientAttributeNames(), DataConstants.CLIENT_SCOPE, "cs.");
  32 + fetchAttributes(msg, service, config.getServerAttributeNames(), DataConstants.SERVER_SCOPE, "ss.");
  33 + fetchAttributes(msg, service, config.getSharedAttributeNames(), DataConstants.SHARED_SCOPE, "shared.");
  34 + ctx.tellNext(msg);
  35 + } catch (Exception e) {
  36 + log.warn("[{}][{}] Failed to fetch attributes", msg.getOriginator(), msg.getId(), e);
  37 + throw new TbNodeException(e);
  38 + }
  39 + }
  40 +
  41 + private void fetchAttributes(TbMsg msg, AttributesService service, List<String> attributeNames, String scope, String prefix) throws InterruptedException, java.util.concurrent.ExecutionException {
  42 + if (attributeNames != null && attributeNames.isEmpty()) {
  43 + List<AttributeKvEntry> attributes = service.find(msg.getOriginator(), scope, attributeNames).get();
  44 + attributes.forEach(attr -> msg.getMetaData().putValue(prefix + attr.getKey(), attr.getValueAsString()));
  45 + }
  46 + }
  47 +
  48 + @Override
  49 + public void destroy() {
  50 +
  51 + }
  52 +}
... ...