19 changed files with 497 additions and 2 deletions
@ -0,0 +1,42 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2017 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. |
||||
|
|
||||
|
--> |
||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
|
<modelVersion>4.0.0</modelVersion> |
||||
|
<parent> |
||||
|
<groupId>org.thingsboard</groupId> |
||||
|
<version>1.4.0-SNAPSHOT</version> |
||||
|
<artifactId>thingsboard</artifactId> |
||||
|
</parent> |
||||
|
<groupId>org.thingsboard</groupId> |
||||
|
<artifactId>rule-engine</artifactId> |
||||
|
<packaging>pom</packaging> |
||||
|
|
||||
|
<name>Thingsboard Extensions</name> |
||||
|
<url>https://thingsboard.io</url> |
||||
|
|
||||
|
<properties> |
||||
|
<main.dir>${basedir}/..</main.dir> |
||||
|
</properties> |
||||
|
|
||||
|
<modules> |
||||
|
<module>rule-engine-api</module> |
||||
|
<module>rule-engine-components</module> |
||||
|
</modules> |
||||
|
|
||||
|
</project> |
||||
@ -0,0 +1,67 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2017 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. |
||||
|
|
||||
|
--> |
||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
|
<modelVersion>4.0.0</modelVersion> |
||||
|
<parent> |
||||
|
<groupId>org.thingsboard</groupId> |
||||
|
<version>1.4.0-SNAPSHOT</version> |
||||
|
<artifactId>rule-engine</artifactId> |
||||
|
</parent> |
||||
|
<groupId>org.thingsboard.rule-engine</groupId> |
||||
|
<artifactId>rule-engine-api</artifactId> |
||||
|
<packaging>jar</packaging> |
||||
|
|
||||
|
<name>Thingsboard Rule Engine API</name> |
||||
|
<url>https://thingsboard.io</url> |
||||
|
|
||||
|
<properties> |
||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||
|
<main.dir>${basedir}/../..</main.dir> |
||||
|
</properties> |
||||
|
|
||||
|
<dependencies> |
||||
|
<dependency> |
||||
|
<groupId>org.thingsboard.common</groupId> |
||||
|
<artifactId>message</artifactId> |
||||
|
<scope>provided</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.thingsboard</groupId> |
||||
|
<artifactId>extensions-api</artifactId> |
||||
|
<scope>provided</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.thingsboard</groupId> |
||||
|
<artifactId>dao</artifactId> |
||||
|
<scope>provided</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>ch.qos.logback</groupId> |
||||
|
<artifactId>logback-core</artifactId> |
||||
|
<scope>provided</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>ch.qos.logback</groupId> |
||||
|
<artifactId>logback-classic</artifactId> |
||||
|
<scope>provided</scope> |
||||
|
</dependency> |
||||
|
</dependencies> |
||||
|
</project> |
||||
@ -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(); |
||||
|
|
||||
|
} |
||||
@ -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; |
||||
|
|
||||
|
} |
||||
@ -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<String, String> data; |
||||
|
|
||||
|
public String getValue(String key) { |
||||
|
return data.get(key); |
||||
|
} |
||||
|
|
||||
|
public void putValue(String key, String value) { |
||||
|
data.put(key, value); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -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(); |
||||
|
|
||||
|
} |
||||
@ -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; |
||||
|
|
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
package org.thingsboard.rule.engine.api; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 19.01.18. |
||||
|
*/ |
||||
|
public class TbNodeState { |
||||
|
} |
||||
@ -0,0 +1,67 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2017 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. |
||||
|
|
||||
|
--> |
||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
|
<modelVersion>4.0.0</modelVersion> |
||||
|
<parent> |
||||
|
<groupId>org.thingsboard</groupId> |
||||
|
<version>1.4.0-SNAPSHOT</version> |
||||
|
<artifactId>rule-engine</artifactId> |
||||
|
</parent> |
||||
|
<groupId>org.thingsboard.rule-engine</groupId> |
||||
|
<artifactId>rule-engine-components</artifactId> |
||||
|
<packaging>jar</packaging> |
||||
|
|
||||
|
<name>Thingsboard Rule Engine Components</name> |
||||
|
<url>https://thingsboard.io</url> |
||||
|
|
||||
|
<properties> |
||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||
|
<main.dir>${basedir}/../..</main.dir> |
||||
|
</properties> |
||||
|
|
||||
|
<dependencies> |
||||
|
<dependency> |
||||
|
<groupId>org.thingsboard</groupId> |
||||
|
<artifactId>dao</artifactId> |
||||
|
<scope>provided</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>ch.qos.logback</groupId> |
||||
|
<artifactId>logback-core</artifactId> |
||||
|
<scope>provided</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>ch.qos.logback</groupId> |
||||
|
<artifactId>logback-classic</artifactId> |
||||
|
<scope>provided</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.thingsboard</groupId> |
||||
|
<artifactId>extensions-api</artifactId> |
||||
|
<scope>provided</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.thingsboard.rule-engine</groupId> |
||||
|
<artifactId>rule-engine-api</artifactId> |
||||
|
<version>1.4.0-SNAPSHOT</version> |
||||
|
</dependency> |
||||
|
</dependencies> |
||||
|
</project> |
||||
@ -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> T convert(TbNodeConfiguration configuration, Class<T> clazz) throws TbNodeException { |
||||
|
try { |
||||
|
return mapper.treeToValue(configuration.getData(), clazz); |
||||
|
} catch (JsonProcessingException e) { |
||||
|
throw new TbNodeException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -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() { |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -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<String> messageTypes; |
||||
|
|
||||
|
} |
||||
@ -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<String> attributeNames, String scope, String prefix) throws InterruptedException, java.util.concurrent.ExecutionException { |
||||
|
if (attributeNames != null && attributeNames.isEmpty()) { |
||||
|
List<AttributeKvEntry> attributes = service.find(msg.getOriginator(), scope, attributeNames).get(); |
||||
|
attributes.forEach(attr -> msg.getMetaData().putValue(prefix + attr.getKey(), attr.getValueAsString())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void destroy() { |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -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<String> clientAttributeNames; |
||||
|
private List<String> sharedAttributeNames; |
||||
|
private List<String> serverAttributeNames; |
||||
|
|
||||
|
} |
||||
@ -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<String> attributeNames, String scope, String prefix) throws InterruptedException, java.util.concurrent.ExecutionException { |
||||
|
if (attributeNames != null && attributeNames.isEmpty()) { |
||||
|
List<AttributeKvEntry> attributes = service.find(msg.getOriginator(), scope, attributeNames).get(); |
||||
|
attributes.forEach(attr -> msg.getMetaData().putValue(prefix + attr.getKey(), attr.getValueAsString())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void destroy() { |
||||
|
|
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue