Browse Source

Merge pull request #748 from thingsboard/develop/1.5-queue

Queue Put and Ack
pull/751/head
Andrew Shvayka 9 years ago
committed by GitHub
parent
commit
0b4ec2b9b3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  2. 53
      application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
  3. 3
      application/src/main/java/org/thingsboard/server/actors/device/PendingSessionMsgData.java
  4. 4
      application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
  5. 90
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
  6. 40
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainToRuleChainMsg.java
  7. 27
      application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java
  8. 2
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  9. 2
      application/src/main/java/org/thingsboard/server/service/script/NashornJsEngine.java
  10. 4
      application/src/test/java/org/thingsboard/server/controller/BaseComponentDescriptorControllerTest.java
  11. 2
      application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java
  12. 1
      application/src/test/java/org/thingsboard/server/mqtt/rpc/sql/MqttServerSideRpcSqlIntegrationTest.java
  13. 2
      application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java
  14. 3
      application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java
  15. 14
      application/src/test/java/org/thingsboard/server/service/script/NashornJsEngineTest.java
  16. 5
      common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java
  17. 42
      common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java
  18. 17
      common/message/src/main/proto/tbmsg.proto
  19. 2
      dao/src/main/java/org/thingsboard/server/dao/queue/MsgQueue.java
  20. 15
      dao/src/main/java/org/thingsboard/server/dao/queue/QueueBenchmark.java
  21. 4
      dao/src/main/java/org/thingsboard/server/dao/service/queue/cassandra/CassandraMsgQueue.java
  22. 50
      dao/src/main/java/org/thingsboard/server/dao/sql/queue/DummySqlMsgQueue.java
  23. 4
      dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/UnprocessedMsgFilterTest.java
  24. 11
      dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/repository/impl/CassandraMsgRepositoryTest.java
  25. 10
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAlarmNode.java
  26. 8
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java
  27. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java
  28. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java
  29. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java
  30. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java
  31. 106
      rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java
  32. 11
      rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java
  33. 7
      rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java
  34. 27
      rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java
  35. 22
      rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java
  36. 43
      rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java
  37. 18
      rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java

5
application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java

@ -49,6 +49,7 @@ import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.dao.plugin.PluginService; import org.thingsboard.server.dao.plugin.PluginService;
import org.thingsboard.server.dao.queue.MsgQueue;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.rule.RuleService; import org.thingsboard.server.dao.rule.RuleService;
@ -187,6 +188,10 @@ public class ActorSystemContext {
@Getter @Getter
private MailService mailService; private MailService mailService;
@Autowired
@Getter
private MsgQueue msgQueue;
@Value("${actors.session.sync.timeout}") @Value("${actors.session.sync.timeout}")
@Getter @Getter
private long syncSessionTimeout; private long syncSessionTimeout;

53
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java

@ -204,9 +204,13 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
void processQueueAck(ActorContext context, RuleEngineQueuePutAckMsg msg) { void processQueueAck(ActorContext context, RuleEngineQueuePutAckMsg msg) {
PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); PendingSessionMsgData data = pendingMsgs.remove(msg.getId());
if (data != null && data.isReplyOnQueueAck()) { if (data != null && data.isReplyOnQueueAck()) {
logger.debug("[{}] Queue put [{}] ack detected!", deviceId, msg.getId()); int remainingAcks = data.getAckMsgCount() - 1;
ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onSuccess(data.getSessionMsgType(), data.getRequestId()); data.setAckMsgCount(remainingAcks);
sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress()); logger.debug("[{}] Queue put [{}] ack detected. Remaining acks: {}!", deviceId, msg.getId(), remainingAcks);
if (remainingAcks == 0) {
ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onSuccess(data.getSessionMsgType(), data.getRequestId());
sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress());
}
} }
} }
@ -320,8 +324,10 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
kv.getStrValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); kv.getStrValue().ifPresent(v -> json.addProperty(kv.getKey(), v));
} }
TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json)); TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L);
pushToRuleEngineWithTimeout(context, tbMsg, src, request); PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(),
SessionMsgType.POST_ATTRIBUTES_REQUEST, request.getRequestId(), true, 1);
pushToRuleEngineWithTimeout(context, tbMsg, msgData);
} }
private void handlePostTelemetryRequest(ActorContext context, DeviceToDeviceActorMsg src) { private void handlePostTelemetryRequest(ActorContext context, DeviceToDeviceActorMsg src) {
@ -329,10 +335,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
Map<Long, List<KvEntry>> tsData = request.getData(); Map<Long, List<KvEntry>> tsData = request.getData();
JsonArray json = new JsonArray(); PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(),
SessionMsgType.POST_TELEMETRY_REQUEST, request.getRequestId(), true, tsData.size());
for (Map.Entry<Long, List<KvEntry>> entry : tsData.entrySet()) { for (Map.Entry<Long, List<KvEntry>> entry : tsData.entrySet()) {
JsonObject ts = new JsonObject(); JsonObject json = new JsonObject();
ts.addProperty("ts", entry.getKey()); json.addProperty("ts", entry.getKey());
JsonObject values = new JsonObject(); JsonObject values = new JsonObject();
for (KvEntry kv : entry.getValue()) { for (KvEntry kv : entry.getValue()) {
kv.getBooleanValue().ifPresent(v -> values.addProperty(kv.getKey(), v)); kv.getBooleanValue().ifPresent(v -> values.addProperty(kv.getKey(), v));
@ -340,12 +348,10 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
kv.getDoubleValue().ifPresent(v -> values.addProperty(kv.getKey(), v)); kv.getDoubleValue().ifPresent(v -> values.addProperty(kv.getKey(), v));
kv.getStrValue().ifPresent(v -> values.addProperty(kv.getKey(), v)); kv.getStrValue().ifPresent(v -> values.addProperty(kv.getKey(), v));
} }
ts.add("values", values); json.add("values", values);
json.add(ts); TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L);
pushToRuleEngineWithTimeout(context, tbMsg, msgData);
} }
TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json));
pushToRuleEngineWithTimeout(context, tbMsg, src, request);
} }
private void handleClientSideRPCRequest(ActorContext context, DeviceToDeviceActorMsg src) { private void handleClientSideRPCRequest(ActorContext context, DeviceToDeviceActorMsg src) {
@ -357,8 +363,9 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
TbMsgMetaData requestMetaData = defaultMetaData.copy(); TbMsgMetaData requestMetaData = defaultMetaData.copy();
requestMetaData.putValue("requestId", Integer.toString(request.getRequestId())); requestMetaData.putValue("requestId", Integer.toString(request.getRequestId()));
TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json)); TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L);
pushToRuleEngineWithTimeout(context, tbMsg, src, request); PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), SessionMsgType.TO_SERVER_RPC_REQUEST, request.getRequestId(), false, 1);
pushToRuleEngineWithTimeout(context, tbMsg, msgData);
scheduleMsgWithDelay(context, new DeviceActorClientSideRpcTimeoutMsg(request.getRequestId(), systemContext.getClientSideRpcTimeout()), systemContext.getClientSideRpcTimeout()); scheduleMsgWithDelay(context, new DeviceActorClientSideRpcTimeoutMsg(request.getRequestId(), systemContext.getClientSideRpcTimeout()), systemContext.getClientSideRpcTimeout());
toServerRpcPendingMap.put(request.getRequestId(), new ToServerRpcRequestMetadata(src.getSessionId(), src.getSessionType(), src.getServerAddress())); toServerRpcPendingMap.put(request.getRequestId(), new ToServerRpcRequestMetadata(src.getSessionId(), src.getSessionType(), src.getServerAddress()));
@ -380,19 +387,15 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
} }
} }
private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, DeviceToDeviceActorMsg src, FromDeviceRequestMsg fromDeviceRequestMsg) { private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, PendingSessionMsgData pendingMsgData) {
pushToRuleEngineWithTimeout(context, tbMsg, src, fromDeviceRequestMsg, true); SessionMsgType sessionMsgType = pendingMsgData.getSessionMsgType();
} int requestId = pendingMsgData.getRequestId();
private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, DeviceToDeviceActorMsg src, FromDeviceRequestMsg fromDeviceRequestMsg, boolean replyOnAck) {
SessionMsgType sessionMsgType = fromDeviceRequestMsg.getMsgType();
int requestId = fromDeviceRequestMsg.getRequestId();
if (systemContext.isQueuePersistenceEnabled()) { if (systemContext.isQueuePersistenceEnabled()) {
pendingMsgs.put(tbMsg.getId(), new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), sessionMsgType, requestId, replyOnAck)); pendingMsgs.put(tbMsg.getId(), pendingMsgData);
scheduleMsgWithDelay(context, new DeviceActorQueueTimeoutMsg(tbMsg.getId(), systemContext.getQueuePersistenceTimeout()), systemContext.getQueuePersistenceTimeout()); scheduleMsgWithDelay(context, new DeviceActorQueueTimeoutMsg(tbMsg.getId(), systemContext.getQueuePersistenceTimeout()), systemContext.getQueuePersistenceTimeout());
} else { } else {
ToDeviceSessionActorMsg response = new BasicToDeviceSessionActorMsg(BasicStatusCodeResponse.onSuccess(sessionMsgType, requestId), src.getSessionId()); ToDeviceSessionActorMsg response = new BasicToDeviceSessionActorMsg(BasicStatusCodeResponse.onSuccess(sessionMsgType, requestId), pendingMsgData.getSessionId());
sendMsgToSessionActor(response, src.getServerAddress()); sendMsgToSessionActor(response, pendingMsgData.getServerAddress());
} }
context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self());
} }

3
application/src/main/java/org/thingsboard/server/actors/device/PendingSessionMsgData.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.actors.device; package org.thingsboard.server.actors.device;
import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.id.SessionId; import org.thingsboard.server.common.data.id.SessionId;
import org.thingsboard.server.common.msg.cluster.ServerAddress; import org.thingsboard.server.common.msg.cluster.ServerAddress;
@ -26,6 +27,7 @@ import java.util.Optional;
* Created by ashvayka on 17.04.18. * Created by ashvayka on 17.04.18.
*/ */
@Data @Data
@AllArgsConstructor
public final class PendingSessionMsgData { public final class PendingSessionMsgData {
private final SessionId sessionId; private final SessionId sessionId;
@ -33,5 +35,6 @@ public final class PendingSessionMsgData {
private final SessionMsgType sessionMsgType; private final SessionMsgType sessionMsgType;
private final int requestId; private final int requestId;
private final boolean replyOnQueueAck; private final boolean replyOnQueueAck;
private int ackMsgCount;
} }

4
application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java

@ -53,7 +53,6 @@ import java.util.function.Consumer;
*/ */
class DefaultTbContext implements TbContext { class DefaultTbContext implements TbContext {
private static final Function<? super List<Void>, ? extends Void> LIST_VOID_FUNCTION = v -> null;
private final ActorSystemContext mainCtx; private final ActorSystemContext mainCtx;
private final RuleNodeCtx nodeCtx; private final RuleNodeCtx nodeCtx;
@ -120,7 +119,7 @@ class DefaultTbContext implements TbContext {
@Override @Override
public TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { public TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) {
return new TbMsg(UUIDs.timeBased(), type, originator, metaData, data); return new TbMsg(UUIDs.timeBased(), type, originator, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId(), 0L);
} }
@Override @Override
@ -239,7 +238,6 @@ class DefaultTbContext implements TbContext {
.build()); .build());
}); });
} }
}; };
} }
} }

90
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java

@ -19,6 +19,7 @@ import akka.actor.ActorContext;
import akka.actor.ActorRef; import akka.actor.ActorRef;
import akka.actor.Props; import akka.actor.Props;
import akka.event.LoggingAdapter; import akka.event.LoggingAdapter;
import com.datastax.driver.core.utils.UUIDs;
import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg;
import org.thingsboard.server.actors.device.RuleEngineQueuePutAckMsg; import org.thingsboard.server.actors.device.RuleEngineQueuePutAckMsg;
@ -41,6 +42,7 @@ import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -52,6 +54,7 @@ import java.util.stream.Collectors;
*/ */
public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> { public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> {
private static final long DEFAULT_CLUSTER_PARTITION = 0L;
private final ActorRef parent; private final ActorRef parent;
private final ActorRef self; private final ActorRef self;
private final Map<RuleNodeId, RuleNodeCtx> nodeActors; private final Map<RuleNodeId, RuleNodeCtx> nodeActors;
@ -83,6 +86,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode));
} }
initRoutes(ruleChain, ruleNodeList); initRoutes(ruleChain, ruleNodeList);
//TODO: read all messages from queues of the actors and push then to the corresponding node actors;
started = true; started = true;
} else { } else {
onUpdate(context); onUpdate(context);
@ -142,15 +146,19 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
// Populating the routes map; // Populating the routes map;
for (RuleNode ruleNode : ruleNodeList) { for (RuleNode ruleNode : ruleNodeList) {
List<EntityRelation> relations = service.getRuleNodeRelations(ruleNode.getId()); List<EntityRelation> relations = service.getRuleNodeRelations(ruleNode.getId());
for (EntityRelation relation : relations) { if (relations.size() == 0) {
if (relation.getTo().getEntityType() == EntityType.RULE_NODE) { nodeRoutes.put(ruleNode.getId(), Collections.emptyList());
RuleNodeCtx ruleNodeCtx = nodeActors.get(new RuleNodeId(relation.getTo().getId())); } else {
if (ruleNodeCtx == null) { for (EntityRelation relation : relations) {
throw new IllegalArgumentException("Rule Node [" + relation.getFrom() + "] has invalid relation to Rule node [" + relation.getTo() + "]"); if (relation.getTo().getEntityType() == EntityType.RULE_NODE) {
RuleNodeCtx ruleNodeCtx = nodeActors.get(new RuleNodeId(relation.getTo().getId()));
if (ruleNodeCtx == null) {
throw new IllegalArgumentException("Rule Node [" + relation.getFrom() + "] has invalid relation to Rule node [" + relation.getTo() + "]");
}
} }
nodeRoutes.computeIfAbsent(ruleNode.getId(), k -> new ArrayList<>())
.add(new RuleNodeRelation(ruleNode.getId(), relation.getTo(), relation.getType()));
} }
nodeRoutes.computeIfAbsent(ruleNode.getId(), k -> new ArrayList<>())
.add(new RuleNodeRelation(ruleNode.getId(), relation.getTo(), relation.getType()));
} }
} }
@ -161,45 +169,62 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg envelope) { void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg envelope) {
checkActive(); checkActive();
TbMsg tbMsg = envelope.getTbMsg(); putToQueue(enrichWithRuleChainId(envelope.getTbMsg()), msg -> pushMsgToNode(firstNode, msg));
//TODO: push to queue and act on ack in async way
pushMsgToNode(firstNode, tbMsg);
} }
public void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg envelope) { void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg envelope) {
checkActive(); checkActive();
TbMsg tbMsg = envelope.getTbMsg(); putToQueue(enrichWithRuleChainId(envelope.getTbMsg()), msg -> {
//TODO: push to queue and act on ack in async way pushMsgToNode(firstNode, msg);
pushMsgToNode(firstNode, tbMsg); envelope.getCallbackRef().tell(new RuleEngineQueuePutAckMsg(msg.getId()), self);
envelope.getCallbackRef().tell(new RuleEngineQueuePutAckMsg(tbMsg.getId()), self); });
} }
void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) { void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) {
checkActive(); checkActive();
RuleNodeId originator = envelope.getOriginator(); RuleNodeId originator = envelope.getOriginator();
String targetRelationType = envelope.getRelationType(); String targetRelationType = envelope.getRelationType();
List<RuleNodeRelation> relations = nodeRoutes.get(originator); List<RuleNodeRelation> relations = nodeRoutes.get(originator).stream()
if (relations == null) { .filter(r -> targetRelationType == null || targetRelationType.equalsIgnoreCase(r.getType()))
return; .collect(Collectors.toList());
}
boolean copy = relations.size() > 1; TbMsg msg = envelope.getMsg();
for (RuleNodeRelation relation : relations) { int relationsCount = relations.size();
TbMsg msg = envelope.getMsg(); if (relationsCount == 0) {
if (copy) { queue.ack(msg, msg.getRuleNodeId().getId(), msg.getClusterPartition());
msg = msg.copy(); } else if (relationsCount == 1) {
for (RuleNodeRelation relation : relations) {
pushToTarget(msg, relation.getOut());
} }
if (targetRelationType == null || targetRelationType.equalsIgnoreCase(relation.getType())) { } else {
switch (relation.getOut().getEntityType()) { for (RuleNodeRelation relation : relations) {
EntityId target = relation.getOut();
switch (target.getEntityType()) {
case RULE_NODE: case RULE_NODE:
RuleNodeId targetRuleNodeId = new RuleNodeId(relation.getOut().getId()); RuleNodeId targetId = new RuleNodeId(target.getId());
RuleNodeCtx targetRuleNode = nodeActors.get(targetRuleNodeId); RuleNodeCtx targetNodeCtx = nodeActors.get(targetId);
pushMsgToNode(targetRuleNode, msg); TbMsg copy = msg.copy(UUIDs.timeBased(), entityId, targetId, DEFAULT_CLUSTER_PARTITION);
putToQueue(copy, queuedMsg -> pushMsgToNode(targetNodeCtx, queuedMsg));
break; break;
case RULE_CHAIN: case RULE_CHAIN:
// TODO: implement parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, msg, true), self);
break; break;
} }
} }
//TODO: Ideally this should happen in async way when all targets confirm that the copied messages are successfully written to corresponding target queues.
EntityId ackId = msg.getRuleNodeId() != null ? msg.getRuleNodeId() : msg.getRuleChainId();
queue.ack(msg, ackId.getId(), msg.getClusterPartition());
}
}
private void pushToTarget(TbMsg msg, EntityId target) {
switch (target.getEntityType()) {
case RULE_NODE:
pushMsgToNode(nodeActors.get(new RuleNodeId(target.getId())), msg);
break;
case RULE_CHAIN:
parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, msg, false), self);
break;
} }
} }
@ -208,4 +233,9 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg), self); nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg), self);
} }
} }
private TbMsg enrichWithRuleChainId(TbMsg tbMsg) {
// We don't put firstNodeId because it may change over time;
return new TbMsg(tbMsg.getId(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.getMetaData(), tbMsg.getData(), entityId, null, 0L);
}
} }

40
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainToRuleChainMsg.java

@ -0,0 +1,40 @@
/**
* 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.actors.ruleChain;
import lombok.Data;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.TbMsg;
/**
* Created by ashvayka on 19.03.18.
*/
@Data
final class RuleChainToRuleChainMsg implements TbActorMsg {
private final RuleChainId target;
private final RuleChainId source;
private final TbMsg msg;
private final boolean enqueue;
@Override
public MsgType getMsgType() {
return MsgType.RULE_CHAIN_TO_RULE_CHAIN_MSG;
}
}

27
application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java

@ -17,22 +17,32 @@ package org.thingsboard.server.actors.shared;
import akka.actor.ActorContext; import akka.actor.ActorContext;
import akka.event.LoggingAdapter; import akka.event.LoggingAdapter;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.stats.StatsPersistTick; import org.thingsboard.server.actors.stats.StatsPersistTick;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.dao.queue.MsgQueue;
public abstract class ComponentMsgProcessor<T> extends AbstractContextAwareMsgProcessor { import javax.annotation.Nullable;
import java.util.function.Consumer;
public abstract class ComponentMsgProcessor<T extends EntityId> extends AbstractContextAwareMsgProcessor {
protected final TenantId tenantId; protected final TenantId tenantId;
protected final T entityId; protected final T entityId;
protected final MsgQueue queue;
protected ComponentLifecycleState state; protected ComponentLifecycleState state;
protected ComponentMsgProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, T id) { protected ComponentMsgProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, T id) {
super(systemContext, logger); super(systemContext, logger);
this.tenantId = tenantId; this.tenantId = tenantId;
this.entityId = id; this.entityId = id;
this.queue = systemContext.getMsgQueue();
} }
public abstract void start(ActorContext context) throws Exception; public abstract void start(ActorContext context) throws Exception;
@ -75,4 +85,19 @@ public abstract class ComponentMsgProcessor<T> extends AbstractContextAwareMsgPr
throw new IllegalStateException("Rule chain is not active!"); throw new IllegalStateException("Rule chain is not active!");
} }
} }
protected void putToQueue(final TbMsg tbMsg, final Consumer<TbMsg> onSuccess) {
EntityId entityId = tbMsg.getRuleNodeId() != null ? tbMsg.getRuleNodeId() : tbMsg.getRuleChainId();
Futures.addCallback(queue.put(tbMsg, entityId.getId(), 0), new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void result) {
onSuccess.accept(tbMsg);
}
@Override
public void onFailure(Throwable t) {
logger.debug("Failed to push message [{}] to queue due to [{}]", tbMsg, t);
}
});
}
} }

2
application/src/main/java/org/thingsboard/server/controller/RuleChainController.java

@ -237,7 +237,7 @@ public class RuleChainController extends BaseController {
ScriptEngine engine = null; ScriptEngine engine = null;
try { try {
engine = new NashornJsEngine(script, functionName, argNames); engine = new NashornJsEngine(script, functionName, argNames);
TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data); TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data, null, null, 0L);
switch (scriptType) { switch (scriptType) {
case "update": case "update":
output = msgToOutput(engine.executeUpdate(inMsg)); output = msgToOutput(engine.executeUpdate(inMsg));

2
application/src/main/java/org/thingsboard/server/service/script/NashornJsEngine.java

@ -118,7 +118,7 @@ public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEn
String newData = data != null ? data : msg.getData(); String newData = data != null ? data : msg.getData();
TbMsgMetaData newMetadata = metadata != null ? new TbMsgMetaData(metadata) : msg.getMetaData(); TbMsgMetaData newMetadata = metadata != null ? new TbMsgMetaData(metadata) : msg.getMetaData();
String newMessageType = !StringUtils.isEmpty(messageType) ? messageType : msg.getType(); String newMessageType = !StringUtils.isEmpty(messageType) ? messageType : msg.getType();
return new TbMsg(msg.getId(), newMessageType, msg.getOriginator(), newMetadata, newData); return new TbMsg(msg.getId(), newMessageType, msg.getOriginator(), newMetadata, newData, msg.getRuleChainId(), msg.getRuleNodeId(), msg.getClusterPartition());
} catch (Throwable th) { } catch (Throwable th) {
th.printStackTrace(); th.printStackTrace();
throw new RuntimeException("Failed to unbind message data from javascript result", th); throw new RuntimeException("Failed to unbind message data from javascript result", th);

4
application/src/test/java/org/thingsboard/server/controller/BaseComponentDescriptorControllerTest.java

@ -36,7 +36,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public abstract class BaseComponentDescriptorControllerTest extends AbstractControllerTest { public abstract class BaseComponentDescriptorControllerTest extends AbstractControllerTest {
private static final int AMOUNT_OF_DEFAULT_FILTER_NODES = 3; private static final int AMOUNT_OF_DEFAULT_FILTER_NODES = 4;
private Tenant savedTenant; private Tenant savedTenant;
private User tenantAdmin; private User tenantAdmin;
@ -87,7 +87,7 @@ public abstract class BaseComponentDescriptorControllerTest extends AbstractCont
}); });
Assert.assertNotNull(descriptors); Assert.assertNotNull(descriptors);
Assert.assertEquals(AMOUNT_OF_DEFAULT_FILTER_NODES, descriptors.size()); Assert.assertTrue(descriptors.size() >= AMOUNT_OF_DEFAULT_FILTER_NODES);
for (ComponentType type : ComponentType.values()) { for (ComponentType type : ComponentType.values()) {
doGet("/api/components/" + type).andExpect(status().isOk()); doGet("/api/components/" + type).andExpect(status().isOk());

2
application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java

@ -80,7 +80,6 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
} }
} }
@Ignore
@Test @Test
public void testServerMqttOneWayRpc() throws Exception { public void testServerMqttOneWayRpc() throws Exception {
Device device = new Device(); Device device = new Device();
@ -107,7 +106,6 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
Assert.assertTrue(StringUtils.isEmpty(result)); Assert.assertTrue(StringUtils.isEmpty(result));
} }
@Ignore
@Test @Test
public void testServerMqttOneWayRpcDeviceOffline() throws Exception { public void testServerMqttOneWayRpcDeviceOffline() throws Exception {
Device device = new Device(); Device device = new Device();

1
application/src/test/java/org/thingsboard/server/mqtt/rpc/sql/MqttServerSideRpcSqlIntegrationTest.java

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.mqtt.rpc.sql; package org.thingsboard.server.mqtt.rpc.sql;
import org.thingsboard.server.dao.service.DaoNoSqlTest;
import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcIntegrationTest; import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcIntegrationTest;

2
application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java

@ -150,7 +150,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
"CUSTOM", "CUSTOM",
device.getId(), device.getId(),
new TbMsgMetaData(), new TbMsgMetaData(),
"{}"); "{}", null, null, 0L);
actorService.onMsg(new ServiceToRuleEngineMsg(savedTenant.getId(), tbMsg)); actorService.onMsg(new ServiceToRuleEngineMsg(savedTenant.getId(), tbMsg));
Thread.sleep(3000); Thread.sleep(3000);

3
application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java

@ -138,7 +138,8 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
"CUSTOM", "CUSTOM",
device.getId(), device.getId(),
new TbMsgMetaData(), new TbMsgMetaData(),
"{}"); "{}",
null, null, 0L);
actorService.onMsg(new ServiceToRuleEngineMsg(savedTenant.getId(), tbMsg)); actorService.onMsg(new ServiceToRuleEngineMsg(savedTenant.getId(), tbMsg));
Thread.sleep(3000); Thread.sleep(3000);

14
application/src/test/java/org/thingsboard/server/service/script/NashornJsEngineTest.java

@ -42,7 +42,7 @@ public class NashornJsEngineTest {
metaData.putValue("humidity", "99"); metaData.putValue("humidity", "99");
String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L);
TbMsg actual = scriptEngine.executeUpdate(msg); TbMsg actual = scriptEngine.executeUpdate(msg);
assertEquals("70", actual.getMetaData().getValue("temp")); assertEquals("70", actual.getMetaData().getValue("temp"));
@ -57,7 +57,7 @@ public class NashornJsEngineTest {
metaData.putValue("humidity", "99"); metaData.putValue("humidity", "99");
String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L);
TbMsg actual = scriptEngine.executeUpdate(msg); TbMsg actual = scriptEngine.executeUpdate(msg);
assertEquals("94", actual.getMetaData().getValue("newAttr")); assertEquals("94", actual.getMetaData().getValue("newAttr"));
@ -72,7 +72,7 @@ public class NashornJsEngineTest {
metaData.putValue("humidity", "99"); metaData.putValue("humidity", "99");
String rawJson = "{\"name\":\"Vit\",\"passed\": 5,\"bigObj\":{\"prop\":42}}"; String rawJson = "{\"name\":\"Vit\",\"passed\": 5,\"bigObj\":{\"prop\":42}}";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L);
TbMsg actual = scriptEngine.executeUpdate(msg); TbMsg actual = scriptEngine.executeUpdate(msg);
@ -89,7 +89,7 @@ public class NashornJsEngineTest {
metaData.putValue("humidity", "99"); metaData.putValue("humidity", "99");
String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L);
assertFalse(scriptEngine.executeFilter(msg)); assertFalse(scriptEngine.executeFilter(msg));
} }
@ -102,7 +102,7 @@ public class NashornJsEngineTest {
metaData.putValue("humidity", "99"); metaData.putValue("humidity", "99");
String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L);
assertTrue(scriptEngine.executeFilter(msg)); assertTrue(scriptEngine.executeFilter(msg));
} }
@ -122,7 +122,7 @@ public class NashornJsEngineTest {
metaData.putValue("humidity", "99"); metaData.putValue("humidity", "99");
String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L);
Set<String> actual = scriptEngine.executeSwitch(msg); Set<String> actual = scriptEngine.executeSwitch(msg);
assertEquals(Sets.newHashSet("one"), actual); assertEquals(Sets.newHashSet("one"), actual);
} }
@ -143,7 +143,7 @@ public class NashornJsEngineTest {
metaData.putValue("humidity", "99"); metaData.putValue("humidity", "99");
String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L);
Set<String> actual = scriptEngine.executeSwitch(msg); Set<String> actual = scriptEngine.executeSwitch(msg);
assertEquals(Sets.newHashSet("one", "three"), actual); assertEquals(Sets.newHashSet("one", "three"), actual);
} }

5
common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java

@ -47,6 +47,11 @@ public enum MsgType {
*/ */
RULE_CHAIN_TO_RULE_MSG, RULE_CHAIN_TO_RULE_MSG,
/**
* Message that is sent by RuleChainActor to other RuleChainActor with command to process TbMsg.
*/
RULE_CHAIN_TO_RULE_CHAIN_MSG,
/** /**
* Message that is sent by RuleActor to RuleChainActor with command to process TbMsg by next nodes in chain. * Message that is sent by RuleActor to RuleChainActor with command to process TbMsg by next nodes in chain.
*/ */

42
common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java

@ -15,12 +15,13 @@
*/ */
package org.thingsboard.server.common.msg; package org.thingsboard.server.common.msg;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.msg.gen.MsgProtos; import org.thingsboard.server.common.msg.gen.MsgProtos;
import java.io.Serializable; import java.io.Serializable;
@ -41,22 +42,40 @@ public final class TbMsg implements Serializable {
private final TbMsgDataType dataType; private final TbMsgDataType dataType;
private final String data; private final String data;
public TbMsg(UUID id, String type, EntityId originator, TbMsgMetaData metaData, String data) { //The following fields are not persisted to DB, because they can always be recovered from the context;
private final RuleChainId ruleChainId;
private final RuleNodeId ruleNodeId;
private final long clusterPartition;
public TbMsg(UUID id, String type, EntityId originator, TbMsgMetaData metaData, String data,
RuleChainId ruleChainId, RuleNodeId ruleNodeId, long clusterPartition) {
this.id = id; this.id = id;
this.type = type; this.type = type;
this.originator = originator; this.originator = originator;
this.metaData = metaData; this.metaData = metaData;
this.dataType = TbMsgDataType.JSON;
this.data = data; this.data = data;
this.dataType = TbMsgDataType.JSON;
this.ruleChainId = ruleChainId;
this.ruleNodeId = ruleNodeId;
this.clusterPartition = clusterPartition;
} }
public static ByteBuffer toBytes(TbMsg msg) { public static ByteBuffer toBytes(TbMsg msg) {
MsgProtos.TbMsgProto.Builder builder = MsgProtos.TbMsgProto.newBuilder(); MsgProtos.TbMsgProto.Builder builder = MsgProtos.TbMsgProto.newBuilder();
builder.setId(msg.getId().toString()); builder.setId(msg.getId().toString());
builder.setType(msg.getType()); builder.setType(msg.getType());
if (msg.getOriginator() != null) { builder.setEntityType(msg.getOriginator().getEntityType().name());
builder.setEntityType(msg.getOriginator().getEntityType().name()); builder.setEntityIdMSB(msg.getOriginator().getId().getMostSignificantBits());
builder.setEntityId(msg.getOriginator().getId().toString()); builder.setEntityIdLSB(msg.getOriginator().getId().getLeastSignificantBits());
if (msg.getRuleChainId() != null) {
builder.setRuleChainIdMSB(msg.getRuleChainId().getId().getMostSignificantBits());
builder.setRuleChainIdLSB(msg.getRuleChainId().getId().getLeastSignificantBits());
}
if (msg.getRuleNodeId() != null) {
builder.setRuleNodeIdMSB(msg.getRuleNodeId().getId().getMostSignificantBits());
builder.setRuleNodeIdLSB(msg.getRuleNodeId().getId().getLeastSignificantBits());
} }
if (msg.getMetaData() != null) { if (msg.getMetaData() != null) {
@ -73,15 +92,18 @@ public final class TbMsg implements Serializable {
try { try {
MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(buffer.array()); MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(buffer.array());
TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap()); TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap());
EntityId entityId = EntityIdFactory.getByTypeAndId(proto.getEntityType(), proto.getEntityId()); EntityId entityId = EntityIdFactory.getByTypeAndUuid(proto.getEntityType(), new UUID(proto.getEntityIdMSB(), proto.getEntityIdLSB()));
RuleChainId ruleChainId = new RuleChainId(new UUID(proto.getRuleChainIdMSB(), proto.getRuleChainIdLSB()));
RuleNodeId ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleChainIdLSB()));
TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()];
return new TbMsg(UUID.fromString(proto.getId()), proto.getType(), entityId, metaData, dataType, proto.getData()); return new TbMsg(UUID.fromString(proto.getId()), proto.getType(), entityId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, proto.getClusterPartition());
} catch (InvalidProtocolBufferException e) { } catch (InvalidProtocolBufferException e) {
throw new IllegalStateException("Could not parse protobuf for TbMsg", e); throw new IllegalStateException("Could not parse protobuf for TbMsg", e);
} }
} }
public TbMsg copy() { public TbMsg copy(UUID newId, RuleChainId ruleChainId, RuleNodeId ruleNodeId, long clusterPartition) {
return new TbMsg(id, type, originator, metaData.copy(), dataType, data); return new TbMsg(newId, type, originator, metaData, dataType, data, ruleChainId, ruleNodeId, clusterPartition);
} }
} }

17
common/message/src/main/proto/tbmsg.proto

@ -27,10 +27,19 @@ message TbMsgProto {
string id = 1; string id = 1;
string type = 2; string type = 2;
string entityType = 3; string entityType = 3;
string entityId = 4; int64 entityIdMSB = 4;
int64 entityIdLSB = 5;
TbMsgMetaDataProto metaData = 5; int64 ruleChainIdMSB = 6;
int64 ruleChainIdLSB = 7;
int64 ruleNodeIdMSB = 8;
int64 ruleNodeIdLSB = 9;
int64 clusterPartition = 10;
TbMsgMetaDataProto metaData = 11;
int32 dataType = 12;
string data = 13;
int32 dataType = 6;
string data = 7;
} }

2
dao/src/main/java/org/thingsboard/server/dao/queue/MsqQueue.java → dao/src/main/java/org/thingsboard/server/dao/queue/MsgQueue.java

@ -20,7 +20,7 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.UUID; import java.util.UUID;
public interface MsqQueue { public interface MsgQueue {
ListenableFuture<Void> put(TbMsg msg, UUID nodeId, long clusterPartition); ListenableFuture<Void> put(TbMsg msg, UUID nodeId, long clusterPartition);

15
dao/src/main/java/org/thingsboard/server/dao/queue/QueueBenchmark.java

@ -27,10 +27,9 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner; import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -61,11 +60,11 @@ public class QueueBenchmark implements CommandLineRunner {
} }
@Autowired @Autowired
private MsqQueue msqQueue; private MsgQueue msgQueue;
@Override @Override
public void run(String... strings) throws Exception { public void run(String... strings) throws Exception {
System.out.println("It works + " + msqQueue); System.out.println("It works + " + msgQueue);
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
@ -81,8 +80,8 @@ public class QueueBenchmark implements CommandLineRunner {
try { try {
TbMsg msg = randomMsg(); TbMsg msg = randomMsg();
UUID nodeId = UUIDs.timeBased(); UUID nodeId = UUIDs.timeBased();
ListenableFuture<Void> put = msqQueue.put(msg, nodeId, 100L); ListenableFuture<Void> put = msgQueue.put(msg, nodeId, 100L);
// ListenableFuture<Void> put = msqQueue.ack(msg, nodeId, 100L); // ListenableFuture<Void> put = msgQueue.ack(msg, nodeId, 100L);
Futures.addCallback(put, new FutureCallback<Void>() { Futures.addCallback(put, new FutureCallback<Void>() {
@Override @Override
public void onSuccess(@Nullable Void result) { public void onSuccess(@Nullable Void result) {
@ -126,7 +125,7 @@ public class QueueBenchmark implements CommandLineRunner {
TbMsgMetaData metaData = new TbMsgMetaData(); TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue("key", "value"); metaData.putValue("key", "value");
String dataStr = "someContent"; String dataStr = "someContent";
return new TbMsg(UUIDs.timeBased(), "type", null, metaData, TbMsgDataType.JSON, dataStr); return new TbMsg(UUIDs.timeBased(), "type", null, metaData, TbMsgDataType.JSON, dataStr, new RuleChainId(UUIDs.timeBased()), new RuleNodeId(UUIDs.timeBased()), 0L);
} }
@Bean @Bean

4
dao/src/main/java/org/thingsboard/server/dao/service/queue/cassandra/CassandraMsqQueue.java → dao/src/main/java/org/thingsboard/server/dao/service/queue/cassandra/CassandraMsgQueue.java

@ -22,7 +22,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.dao.queue.MsqQueue; import org.thingsboard.server.dao.queue.MsgQueue;
import org.thingsboard.server.dao.service.queue.cassandra.repository.AckRepository; import org.thingsboard.server.dao.service.queue.cassandra.repository.AckRepository;
import org.thingsboard.server.dao.service.queue.cassandra.repository.MsgRepository; import org.thingsboard.server.dao.service.queue.cassandra.repository.MsgRepository;
import org.thingsboard.server.dao.util.NoSqlDao; import org.thingsboard.server.dao.util.NoSqlDao;
@ -33,7 +33,7 @@ import java.util.UUID;
@Component @Component
@Slf4j @Slf4j
@NoSqlDao @NoSqlDao
public class CassandraMsqQueue implements MsqQueue { public class CassandraMsgQueue implements MsgQueue {
@Autowired @Autowired
private MsgRepository msgRepository; private MsgRepository msgRepository;

50
dao/src/main/java/org/thingsboard/server/dao/sql/queue/DummySqlMsgQueue.java

@ -0,0 +1,50 @@
/**
* 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.dao.sql.queue;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.dao.queue.MsgQueue;
import org.thingsboard.server.dao.util.SqlDao;
import java.util.Collections;
import java.util.UUID;
/**
* Created by ashvayka on 27.04.18.
*/
@Component
@Slf4j
@SqlDao
public class DummySqlMsgQueue implements MsgQueue {
@Override
public ListenableFuture<Void> put(TbMsg msg, UUID nodeId, long clusterPartition) {
return Futures.immediateFuture(null);
}
@Override
public ListenableFuture<Void> ack(TbMsg msg, UUID nodeId, long clusterPartition) {
return Futures.immediateFuture(null);
}
@Override
public Iterable<TbMsg> findUnprocessed(UUID nodeId, long clusterPartition) {
return Collections.emptyList();
}
}

4
dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/UnprocessedMsgFilterTest.java

@ -33,8 +33,8 @@ public class UnprocessedMsgFilterTest {
public void acknowledgedMsgsAreFilteredOut() { public void acknowledgedMsgsAreFilteredOut() {
UUID id1 = UUID.randomUUID(); UUID id1 = UUID.randomUUID();
UUID id2 = UUID.randomUUID(); UUID id2 = UUID.randomUUID();
TbMsg msg1 = new TbMsg(id1, "T", null, null, null, null); TbMsg msg1 = new TbMsg(id1, "T", null, null, null, null, null, null, 0L);
TbMsg msg2 = new TbMsg(id2, "T", null, null, null, null); TbMsg msg2 = new TbMsg(id2, "T", null, null, null, null, null, null, 0L);
List<TbMsg> msgs = Lists.newArrayList(msg1, msg2); List<TbMsg> msgs = Lists.newArrayList(msg1, msg2);
List<MsgAck> acks = Lists.newArrayList(new MsgAck(id2, UUID.randomUUID(), 1L, 1L)); List<MsgAck> acks = Lists.newArrayList(new MsgAck(id2, UUID.randomUUID(), 1L, 1L));
Collection<TbMsg> actual = msgFilter.filter(msgs, acks); Collection<TbMsg> actual = msgFilter.filter(msgs, acks);

11
dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/repository/impl/CassandraMsgRepositoryTest.java

@ -23,6 +23,8 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -45,7 +47,8 @@ public class CassandraMsgRepositoryTest extends AbstractServiceTest {
@Test @Test
public void msgCanBeSavedAndRead() throws ExecutionException, InterruptedException { public void msgCanBeSavedAndRead() throws ExecutionException, InterruptedException {
TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, TbMsgDataType.JSON, "0000"); TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, TbMsgDataType.JSON, "0000",
new RuleChainId(UUIDs.timeBased()), new RuleNodeId(UUIDs.timeBased()), 0L);
UUID nodeId = UUIDs.timeBased(); UUID nodeId = UUIDs.timeBased();
ListenableFuture<Void> future = msgRepository.save(msg, nodeId, 1L, 1L, 1L); ListenableFuture<Void> future = msgRepository.save(msg, nodeId, 1L, 1L, 1L);
future.get(); future.get();
@ -55,7 +58,8 @@ public class CassandraMsgRepositoryTest extends AbstractServiceTest {
@Test @Test
public void expiredMsgsAreNotReturned() throws ExecutionException, InterruptedException { public void expiredMsgsAreNotReturned() throws ExecutionException, InterruptedException {
TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, TbMsgDataType.JSON, "0000"); TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, TbMsgDataType.JSON, "0000",
new RuleChainId(UUIDs.timeBased()), new RuleNodeId(UUIDs.timeBased()), 0L);
UUID nodeId = UUIDs.timeBased(); UUID nodeId = UUIDs.timeBased();
ListenableFuture<Void> future = msgRepository.save(msg, nodeId, 2L, 2L, 2L); ListenableFuture<Void> future = msgRepository.save(msg, nodeId, 2L, 2L, 2L);
future.get(); future.get();
@ -68,7 +72,8 @@ public class CassandraMsgRepositoryTest extends AbstractServiceTest {
TbMsgMetaData metaData = new TbMsgMetaData(); TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue("key", "value"); metaData.putValue("key", "value");
String dataStr = "someContent"; String dataStr = "someContent";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), metaData, TbMsgDataType.JSON, dataStr); TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), metaData, TbMsgDataType.JSON, dataStr,
new RuleChainId(UUIDs.timeBased()), new RuleNodeId(UUIDs.timeBased()), 0L);
UUID nodeId = UUIDs.timeBased(); UUID nodeId = UUIDs.timeBased();
ListenableFuture<Void> future = msgRepository.save(msg, nodeId, 1L, 1L, 1L); ListenableFuture<Void> future = msgRepository.save(msg, nodeId, 1L, 1L, 1L);
future.get(); future.get();

10
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAlarmNode.java

@ -91,11 +91,11 @@ public class TbAlarmNode implements TbNode {
if (alarmResult.alarm == null) { if (alarmResult.alarm == null) {
ctx.tellNext(msg, "False"); ctx.tellNext(msg, "False");
} else if (alarmResult.isCreated) { } else if (alarmResult.isCreated) {
ctx.tellNext(toAlarmMsg(alarmResult, msg), "Created"); ctx.tellNext(toAlarmMsg(ctx, alarmResult, msg), "Created");
} else if (alarmResult.isUpdated) { } else if (alarmResult.isUpdated) {
ctx.tellNext(toAlarmMsg(alarmResult, msg), "Updated"); ctx.tellNext(toAlarmMsg(ctx, alarmResult, msg), "Updated");
} else if (alarmResult.isCleared) { } else if (alarmResult.isCleared) {
ctx.tellNext(toAlarmMsg(alarmResult, msg), "Cleared"); ctx.tellNext(toAlarmMsg(ctx, alarmResult, msg), "Cleared");
} }
}, },
t -> ctx.tellError(msg, t)); t -> ctx.tellError(msg, t));
@ -176,7 +176,7 @@ public class TbAlarmNode implements TbNode {
return ctx.getJsExecutor().executeAsync(() -> buildDetailsJsEngine.executeJson(msg)); return ctx.getJsExecutor().executeAsync(() -> buildDetailsJsEngine.executeJson(msg));
} }
private TbMsg toAlarmMsg(AlarmResult alarmResult, TbMsg originalMsg) { private TbMsg toAlarmMsg(TbContext ctx, AlarmResult alarmResult, TbMsg originalMsg) {
JsonNode jsonNodes = mapper.valueToTree(alarmResult.alarm); JsonNode jsonNodes = mapper.valueToTree(alarmResult.alarm);
String data = jsonNodes.toString(); String data = jsonNodes.toString();
TbMsgMetaData metaData = originalMsg.getMetaData().copy(); TbMsgMetaData metaData = originalMsg.getMetaData().copy();
@ -187,7 +187,7 @@ public class TbAlarmNode implements TbNode {
} else if (alarmResult.isCleared) { } else if (alarmResult.isCleared) {
metaData.putValue(IS_CLEARED_ALARM, Boolean.TRUE.toString()); metaData.putValue(IS_CLEARED_ALARM, Boolean.TRUE.toString());
} }
return new TbMsg(UUIDs.timeBased(), "ALARM", originalMsg.getOriginator(), metaData, data); return ctx.newMsg("ALARM", originalMsg.getOriginator(), metaData, data);
} }

8
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java

@ -78,18 +78,18 @@ public class TbMsgGeneratorNode implements TbNode {
} }
private void sentTickMsg(TbContext ctx) { private void sentTickMsg(TbContext ctx) {
TbMsg tickMsg = new TbMsg(UUIDs.timeBased(), TB_MSG_GENERATOR_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), ""); TbMsg tickMsg = ctx.newMsg(TB_MSG_GENERATOR_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), "");
nextTickId = tickMsg.getId(); nextTickId = tickMsg.getId();
ctx.tellSelf(tickMsg, delay); ctx.tellSelf(tickMsg, delay);
} }
protected ListenableFuture<TbMsg> generate(TbContext ctx) { private ListenableFuture<TbMsg> generate(TbContext ctx) {
return ctx.getJsExecutor().executeAsync(() -> { return ctx.getJsExecutor().executeAsync(() -> {
if (prevMsg == null) { if (prevMsg == null) {
prevMsg = new TbMsg(UUIDs.timeBased(), "", originatorId, new TbMsgMetaData(), "{}"); prevMsg = ctx.newMsg( "", originatorId, new TbMsgMetaData(), "{}");
} }
TbMsg generated = jsEngine.executeGenerate(prevMsg); TbMsg generated = jsEngine.executeGenerate(prevMsg);
prevMsg = new TbMsg(UUIDs.timeBased(), generated.getType(), originatorId, generated.getMetaData(), generated.getData()); prevMsg = ctx.newMsg(generated.getType(), originatorId, generated.getMetaData(), generated.getData());
return prevMsg; return prevMsg;
}); });
} }

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java

@ -61,7 +61,7 @@ public class TbJsSwitchNode implements TbNode {
ctx.tellNext(msg, nextRelations); ctx.tellNext(msg, nextRelations);
} }
@Override @Override
public void destroy() { public void destroy() {
if (jsEngine != null) { if (jsEngine != null) {
jsEngine.destroy(); jsEngine.destroy();

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java

@ -76,7 +76,7 @@ public class TbMsgToEmailNode implements TbNode {
public void onMsg(TbContext ctx, TbMsg msg) { public void onMsg(TbContext ctx, TbMsg msg) {
try { try {
EmailPojo email = convert(msg); EmailPojo email = convert(msg);
TbMsg emailMsg = buildEmailMsg(msg, email); TbMsg emailMsg = buildEmailMsg(ctx, msg, email);
ctx.tellNext(emailMsg); ctx.tellNext(emailMsg);
} catch (Exception ex) { } catch (Exception ex) {
log.warn("Can not convert message to email " + ex.getMessage()); log.warn("Can not convert message to email " + ex.getMessage());
@ -84,9 +84,9 @@ public class TbMsgToEmailNode implements TbNode {
} }
} }
private TbMsg buildEmailMsg(TbMsg msg, EmailPojo email) throws JsonProcessingException { private TbMsg buildEmailMsg(TbContext ctx, TbMsg msg, EmailPojo email) throws JsonProcessingException {
String emailJson = MAPPER.writeValueAsString(email); String emailJson = MAPPER.writeValueAsString(email);
return new TbMsg(UUIDs.timeBased(), SEND_EMAIL_TYPE, msg.getOriginator(), msg.getMetaData().copy(), emailJson); return ctx.newMsg(SEND_EMAIL_TYPE, msg.getOriginator(), msg.getMetaData().copy(), emailJson);
} }
private EmailPojo convert(TbMsg msg) throws IOException { private EmailPojo convert(TbMsg msg) throws IOException {

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java

@ -63,8 +63,6 @@ public class TbSendEmailNode implements TbNode {
} catch (Exception ex) { } catch (Exception ex) {
ctx.tellError(msg, ex); ctx.tellError(msg, ex);
} }
} }
private EmailPojo getEmail(TbMsg msg) throws IOException { private EmailPojo getEmail(TbMsg msg) throws IOException {
@ -84,6 +82,5 @@ public class TbSendEmailNode implements TbNode {
@Override @Override
public void destroy() { public void destroy() {
} }
} }

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java

@ -60,7 +60,7 @@ public class TbChangeOriginatorNode extends TbAbstractTransformNode {
@Override @Override
protected ListenableFuture<TbMsg> transform(TbContext ctx, TbMsg msg) { protected ListenableFuture<TbMsg> transform(TbContext ctx, TbMsg msg) {
ListenableFuture<? extends EntityId> newOriginator = getNewOriginator(ctx, msg.getOriginator()); ListenableFuture<? extends EntityId> newOriginator = getNewOriginator(ctx, msg.getOriginator());
return Futures.transform(newOriginator, (Function<EntityId, TbMsg>) n -> new TbMsg(msg.getId(), msg.getType(), n, msg.getMetaData(), msg.getData())); return Futures.transform(newOriginator, (Function<EntityId, TbMsg>) n -> ctx.newMsg(msg.getType(), n, msg.getMetaData(), msg.getData()));
} }
private ListenableFuture<? extends EntityId> getNewOriginator(TbContext ctx, EntityId original) { private ListenableFuture<? extends EntityId> getNewOriginator(TbContext ctx, EntityId original) {

106
rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java

@ -35,6 +35,8 @@ import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -73,6 +75,9 @@ public class TbAlarmNodeTest {
@Mock @Mock
private ScriptEngine detailsJs; private ScriptEngine detailsJs;
private RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased());
private RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased());
private ListeningExecutor dbExecutor; private ListeningExecutor dbExecutor;
private EntityId originator = new DeviceId(UUIDs.timeBased()); private EntityId originator = new DeviceId(UUIDs.timeBased());
@ -103,7 +108,7 @@ public class TbAlarmNodeTest {
public void newAlarmCanBeCreated() throws ScriptException, IOException { public void newAlarmCanBeCreated() throws ScriptException, IOException {
initWithScript(); initWithScript();
metaData.putValue("key", "value"); metaData.putValue("key", "value");
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L);
when(createJs.executeFilter(msg)).thenReturn(true); when(createJs.executeFilter(msg)).thenReturn(true);
when(detailsJs.executeJson(msg)).thenReturn(null); when(detailsJs.executeJson(msg)).thenReturn(null);
@ -113,17 +118,21 @@ public class TbAlarmNodeTest {
node.onMsg(ctx, msg); node.onMsg(ctx, msg);
ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx).tellNext(any(), eq("Created"));
verify(ctx).tellNext(captor.capture(), eq("Created"));
TbMsg actualMsg = captor.getValue(); ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class);
ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class);
ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class);
verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture());
assertEquals("ALARM", actualMsg.getType()); assertEquals("ALARM", typeCaptor.getValue());
assertEquals(originator, actualMsg.getOriginator()); assertEquals(originator, originatorCaptor.getValue());
assertEquals("value", actualMsg.getMetaData().getValue("key")); assertEquals("value", metadataCaptor.getValue().getValue("key"));
assertEquals(Boolean.TRUE.toString(), actualMsg.getMetaData().getValue(IS_NEW_ALARM)); assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_NEW_ALARM));
assertNotSame(metaData, actualMsg.getMetaData()); assertNotSame(metaData, metadataCaptor.getValue());
Alarm actualAlarm = new ObjectMapper().readValue(actualMsg.getData().getBytes(), Alarm.class); Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class);
Alarm expectedAlarm = Alarm.builder() Alarm expectedAlarm = Alarm.builder()
.tenantId(tenantId) .tenantId(tenantId)
.originator(originator) .originator(originator)
@ -143,7 +152,7 @@ public class TbAlarmNodeTest {
public void shouldCreateScriptThrowsException() throws ScriptException { public void shouldCreateScriptThrowsException() throws ScriptException {
initWithScript(); initWithScript();
metaData.putValue("key", "value"); metaData.putValue("key", "value");
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L);
when(createJs.executeFilter(msg)).thenThrow(new NotImplementedException("message")); when(createJs.executeFilter(msg)).thenThrow(new NotImplementedException("message"));
@ -165,7 +174,7 @@ public class TbAlarmNodeTest {
public void buildDetailsThrowsException() throws ScriptException, IOException { public void buildDetailsThrowsException() throws ScriptException, IOException {
initWithScript(); initWithScript();
metaData.putValue("key", "value"); metaData.putValue("key", "value");
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L);
when(createJs.executeFilter(msg)).thenReturn(true); when(createJs.executeFilter(msg)).thenReturn(true);
when(detailsJs.executeJson(msg)).thenThrow(new NotImplementedException("message")); when(detailsJs.executeJson(msg)).thenThrow(new NotImplementedException("message"));
@ -191,7 +200,7 @@ public class TbAlarmNodeTest {
public void ifAlarmClearedCreateNew() throws ScriptException, IOException { public void ifAlarmClearedCreateNew() throws ScriptException, IOException {
initWithScript(); initWithScript();
metaData.putValue("key", "value"); metaData.putValue("key", "value");
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L);
Alarm clearedAlarm = Alarm.builder().status(CLEARED_ACK).build(); Alarm clearedAlarm = Alarm.builder().status(CLEARED_ACK).build();
@ -203,17 +212,22 @@ public class TbAlarmNodeTest {
node.onMsg(ctx, msg); node.onMsg(ctx, msg);
ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx).tellNext(any(), eq("Created"));
verify(ctx).tellNext(captor.capture(), eq("Created"));
TbMsg actualMsg = captor.getValue(); ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class);
ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class);
ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class);
verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture());
assertEquals("ALARM", actualMsg.getType()); assertEquals("ALARM", typeCaptor.getValue());
assertEquals(originator, actualMsg.getOriginator()); assertEquals(originator, originatorCaptor.getValue());
assertEquals("value", actualMsg.getMetaData().getValue("key")); assertEquals("value", metadataCaptor.getValue().getValue("key"));
assertEquals(Boolean.TRUE.toString(), actualMsg.getMetaData().getValue(IS_NEW_ALARM)); assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_NEW_ALARM));
assertNotSame(metaData, actualMsg.getMetaData()); assertNotSame(metaData, metadataCaptor.getValue());
Alarm actualAlarm = new ObjectMapper().readValue(actualMsg.getData().getBytes(), Alarm.class);
Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class);
Alarm expectedAlarm = Alarm.builder() Alarm expectedAlarm = Alarm.builder()
.tenantId(tenantId) .tenantId(tenantId)
.originator(originator) .originator(originator)
@ -233,7 +247,7 @@ public class TbAlarmNodeTest {
public void alarmCanBeUpdated() throws ScriptException, IOException { public void alarmCanBeUpdated() throws ScriptException, IOException {
initWithScript(); initWithScript();
metaData.putValue("key", "value"); metaData.putValue("key", "value");
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L);
long oldEndDate = System.currentTimeMillis(); long oldEndDate = System.currentTimeMillis();
Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).status(ACTIVE_UNACK).severity(WARNING).endTs(oldEndDate).build(); Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).status(ACTIVE_UNACK).severity(WARNING).endTs(oldEndDate).build();
@ -247,17 +261,21 @@ public class TbAlarmNodeTest {
node.onMsg(ctx, msg); node.onMsg(ctx, msg);
ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx).tellNext(any(), eq("Updated"));
verify(ctx).tellNext(captor.capture(), eq("Updated"));
TbMsg actualMsg = captor.getValue(); ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class);
ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class);
ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class);
verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture());
assertEquals("ALARM", actualMsg.getType()); assertEquals("ALARM", typeCaptor.getValue());
assertEquals(originator, actualMsg.getOriginator()); assertEquals(originator, originatorCaptor.getValue());
assertEquals("value", actualMsg.getMetaData().getValue("key")); assertEquals("value", metadataCaptor.getValue().getValue("key"));
assertEquals(Boolean.TRUE.toString(), actualMsg.getMetaData().getValue(IS_EXISTING_ALARM)); assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_EXISTING_ALARM));
assertNotSame(metaData, actualMsg.getMetaData()); assertNotSame(metaData, metadataCaptor.getValue());
Alarm actualAlarm = new ObjectMapper().readValue(actualMsg.getData().getBytes(), Alarm.class); Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class);
assertTrue(activeAlarm.getEndTs() > oldEndDate); assertTrue(activeAlarm.getEndTs() > oldEndDate);
Alarm expectedAlarm = Alarm.builder() Alarm expectedAlarm = Alarm.builder()
.tenantId(tenantId) .tenantId(tenantId)
@ -279,7 +297,7 @@ public class TbAlarmNodeTest {
public void alarmCanBeCleared() throws ScriptException, IOException { public void alarmCanBeCleared() throws ScriptException, IOException {
initWithScript(); initWithScript();
metaData.putValue("key", "value"); metaData.putValue("key", "value");
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L);
long oldEndDate = System.currentTimeMillis(); long oldEndDate = System.currentTimeMillis();
Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).status(ACTIVE_UNACK).severity(WARNING).endTs(oldEndDate).build(); Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).status(ACTIVE_UNACK).severity(WARNING).endTs(oldEndDate).build();
@ -293,17 +311,21 @@ public class TbAlarmNodeTest {
node.onMsg(ctx, msg); node.onMsg(ctx, msg);
ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx).tellNext(any(), eq("Cleared"));
verify(ctx).tellNext(captor.capture(), eq("Cleared"));
TbMsg actualMsg = captor.getValue(); ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class);
ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class);
ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class);
verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture());
assertEquals("ALARM", actualMsg.getType()); assertEquals("ALARM", typeCaptor.getValue());
assertEquals(originator, actualMsg.getOriginator()); assertEquals(originator, originatorCaptor.getValue());
assertEquals("value", actualMsg.getMetaData().getValue("key")); assertEquals("value", metadataCaptor.getValue().getValue("key"));
assertEquals(Boolean.TRUE.toString(), actualMsg.getMetaData().getValue(IS_CLEARED_ALARM)); assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_CLEARED_ALARM));
assertNotSame(metaData, actualMsg.getMetaData()); assertNotSame(metaData, metadataCaptor.getValue());
Alarm actualAlarm = new ObjectMapper().readValue(actualMsg.getData().getBytes(), Alarm.class); Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class);
Alarm expectedAlarm = Alarm.builder() Alarm expectedAlarm = Alarm.builder()
.tenantId(tenantId) .tenantId(tenantId)
.originator(originator) .originator(originator)

11
rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java

@ -27,6 +27,8 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -48,10 +50,13 @@ public class TbJsFilterNodeTest {
@Mock @Mock
private ScriptEngine scriptEngine; private ScriptEngine scriptEngine;
private RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased());
private RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased());
@Test @Test
public void falseEvaluationDoNotSendMsg() throws TbNodeException, ScriptException { public void falseEvaluationDoNotSendMsg() throws TbNodeException, ScriptException {
initWithScript(); initWithScript();
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, new TbMsgMetaData(), "{}"); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
mockJsExecutor(); mockJsExecutor();
when(scriptEngine.executeFilter(msg)).thenReturn(false); when(scriptEngine.executeFilter(msg)).thenReturn(false);
@ -64,7 +69,7 @@ public class TbJsFilterNodeTest {
public void exceptionInJsThrowsException() throws TbNodeException, ScriptException { public void exceptionInJsThrowsException() throws TbNodeException, ScriptException {
initWithScript(); initWithScript();
TbMsgMetaData metaData = new TbMsgMetaData(); TbMsgMetaData metaData = new TbMsgMetaData();
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{}"); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{}", ruleChainId, ruleNodeId, 0L);
mockJsExecutor(); mockJsExecutor();
when(scriptEngine.executeFilter(msg)).thenThrow(new ScriptException("error")); when(scriptEngine.executeFilter(msg)).thenThrow(new ScriptException("error"));
@ -77,7 +82,7 @@ public class TbJsFilterNodeTest {
public void metadataConditionCanBeTrue() throws TbNodeException, ScriptException { public void metadataConditionCanBeTrue() throws TbNodeException, ScriptException {
initWithScript(); initWithScript();
TbMsgMetaData metaData = new TbMsgMetaData(); TbMsgMetaData metaData = new TbMsgMetaData();
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{}"); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{}", ruleChainId, ruleNodeId, 0L);
mockJsExecutor(); mockJsExecutor();
when(scriptEngine.executeFilter(msg)).thenReturn(true); when(scriptEngine.executeFilter(msg)).thenReturn(true);

7
rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java

@ -28,6 +28,8 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -51,6 +53,9 @@ public class TbJsSwitchNodeTest {
@Mock @Mock
private ScriptEngine scriptEngine; private ScriptEngine scriptEngine;
private RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased());
private RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased());
@Test @Test
public void multipleRoutesAreAllowed() throws TbNodeException, ScriptException { public void multipleRoutesAreAllowed() throws TbNodeException, ScriptException {
initWithScript(); initWithScript();
@ -59,7 +64,7 @@ public class TbJsSwitchNodeTest {
metaData.putValue("humidity", "99"); metaData.putValue("humidity", "99");
String rawJson = "{\"name\": \"Vit\", \"passed\": 5}"; String rawJson = "{\"name\": \"Vit\", \"passed\": 5}";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, ruleChainId, ruleNodeId, 0L);
mockJsExecutor(); mockJsExecutor();
when(scriptEngine.executeSwitch(msg)).thenReturn(Sets.newHashSet("one", "three")); when(scriptEngine.executeSwitch(msg)).thenReturn(Sets.newHashSet("one", "three"));

27
rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java

@ -27,6 +27,8 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -34,7 +36,9 @@ import java.io.IOException;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNotSame;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class TbMsgToEmailNodeTest { public class TbMsgToEmailNodeTest {
@ -48,26 +52,31 @@ public class TbMsgToEmailNodeTest {
private TbMsgMetaData metaData = new TbMsgMetaData(); private TbMsgMetaData metaData = new TbMsgMetaData();
private String rawJson = "{\"name\": \"temp\", \"passed\": 5 , \"complex\": {\"val\":12, \"count\":100}}"; private String rawJson = "{\"name\": \"temp\", \"passed\": 5 , \"complex\": {\"val\":12, \"count\":100}}";
private RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased());
private RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased());
@Test @Test
public void msgCanBeConverted() throws IOException { public void msgCanBeConverted() throws IOException {
initWithScript(); initWithScript();
metaData.putValue("username", "oreo"); metaData.putValue("username", "oreo");
metaData.putValue("userEmail", "user@email.io"); metaData.putValue("userEmail", "user@email.io");
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L);
emailNode.onMsg(ctx, msg); emailNode.onMsg(ctx, msg);
ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class);
verify(ctx).tellNext(captor.capture()); ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class);
TbMsg actualMsg = captor.getValue(); ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class);
ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class);
verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture());
assertEquals("SEND_EMAIL", actualMsg.getType());
assertEquals(originator, actualMsg.getOriginator());
assertEquals("oreo", actualMsg.getMetaData().getValue("username"));
assertNotSame(metaData, actualMsg.getMetaData());
assertEquals("SEND_EMAIL", typeCaptor.getValue());
assertEquals(originator, originatorCaptor.getValue());
assertEquals("oreo", metadataCaptor.getValue().getValue("username"));
assertNotSame(metaData, metadataCaptor.getValue());
EmailPojo actual = new ObjectMapper().readValue(actualMsg.getData().getBytes(), EmailPojo.class); EmailPojo actual = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), EmailPojo.class);
EmailPojo expected = new EmailPojo.EmailPojoBuilder() EmailPojo expected = new EmailPojo.EmailPojoBuilder()
.from("test@mail.org") .from("test@mail.org")

22
rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java

@ -34,6 +34,8 @@ import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.kv.*; import org.thingsboard.server.common.data.kv.*;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@ -77,6 +79,9 @@ public class TbGetCustomerAttributeNodeTest {
private TbMsg msg; private TbMsg msg;
private RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased());
private RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased());
@Before @Before
public void init() throws TbNodeException { public void init() throws TbNodeException {
TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration();
@ -98,7 +103,8 @@ public class TbGetCustomerAttributeNodeTest {
User user = new User(); User user = new User();
user.setCustomerId(customerId); user.setCustomerId(customerId);
msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}");
msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
when(ctx.getUserService()).thenReturn(userService); when(ctx.getUserService()).thenReturn(userService);
when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(user)); when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(user));
@ -123,7 +129,7 @@ public class TbGetCustomerAttributeNodeTest {
User user = new User(); User user = new User();
user.setCustomerId(customerId); user.setCustomerId(customerId);
msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}"); msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
when(ctx.getUserService()).thenReturn(userService); when(ctx.getUserService()).thenReturn(userService);
when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(user)); when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(user));
@ -148,7 +154,7 @@ public class TbGetCustomerAttributeNodeTest {
User user = new User(); User user = new User();
user.setCustomerId(customerId); user.setCustomerId(customerId);
msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}"); msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
when(ctx.getUserService()).thenReturn(userService); when(ctx.getUserService()).thenReturn(userService);
when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(null)); when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(null));
@ -166,7 +172,7 @@ public class TbGetCustomerAttributeNodeTest {
@Test @Test
public void customerAttributeAddedInMetadata() { public void customerAttributeAddedInMetadata() {
CustomerId customerId = new CustomerId(UUIDs.timeBased()); CustomerId customerId = new CustomerId(UUIDs.timeBased());
msg = new TbMsg(UUIDs.timeBased(), "CUSTOMER", customerId, new TbMsgMetaData(), "{}"); msg = new TbMsg(UUIDs.timeBased(), "CUSTOMER", customerId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
entityAttributeFetched(customerId); entityAttributeFetched(customerId);
} }
@ -177,7 +183,7 @@ public class TbGetCustomerAttributeNodeTest {
User user = new User(); User user = new User();
user.setCustomerId(customerId); user.setCustomerId(customerId);
msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}"); msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
when(ctx.getUserService()).thenReturn(userService); when(ctx.getUserService()).thenReturn(userService);
when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(user)); when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(user));
@ -192,7 +198,7 @@ public class TbGetCustomerAttributeNodeTest {
Asset asset = new Asset(); Asset asset = new Asset();
asset.setCustomerId(customerId); asset.setCustomerId(customerId);
msg = new TbMsg(UUIDs.timeBased(), "USER", assetId, new TbMsgMetaData(), "{}"); msg = new TbMsg(UUIDs.timeBased(), "USER", assetId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
when(ctx.getAssetService()).thenReturn(assetService); when(ctx.getAssetService()).thenReturn(assetService);
when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFuture(asset)); when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFuture(asset));
@ -207,7 +213,7 @@ public class TbGetCustomerAttributeNodeTest {
Device device = new Device(); Device device = new Device();
device.setCustomerId(customerId); device.setCustomerId(customerId);
msg = new TbMsg(UUIDs.timeBased(), "USER", deviceId, new TbMsgMetaData(), "{}"); msg = new TbMsg(UUIDs.timeBased(), "USER", deviceId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
when(ctx.getDeviceService()).thenReturn(deviceService); when(ctx.getDeviceService()).thenReturn(deviceService);
when(deviceService.findDeviceByIdAsync(deviceId)).thenReturn(Futures.immediateFuture(device)); when(deviceService.findDeviceByIdAsync(deviceId)).thenReturn(Futures.immediateFuture(device));
@ -234,7 +240,7 @@ public class TbGetCustomerAttributeNodeTest {
Device device = new Device(); Device device = new Device();
device.setCustomerId(customerId); device.setCustomerId(customerId);
msg = new TbMsg(UUIDs.timeBased(), "USER", deviceId, new TbMsgMetaData(), "{}"); msg = new TbMsg(UUIDs.timeBased(), "USER", deviceId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
when(ctx.getDeviceService()).thenReturn(deviceService); when(ctx.getDeviceService()).thenReturn(deviceService);
when(deviceService.findDeviceByIdAsync(deviceId)).thenReturn(Futures.immediateFuture(device)); when(deviceService.findDeviceByIdAsync(deviceId)).thenReturn(Futures.immediateFuture(device));

43
rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java

@ -29,6 +29,9 @@ import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
@ -57,17 +60,23 @@ public class TbChangeOriginatorNodeTest {
Asset asset = new Asset(); Asset asset = new Asset();
asset.setCustomerId(customerId); asset.setCustomerId(customerId);
TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}"); RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased());
RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased());
TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
when(ctx.getAssetService()).thenReturn(assetService); when(ctx.getAssetService()).thenReturn(assetService);
when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFuture(asset)); when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFuture(asset));
node.onMsg(ctx, msg); node.onMsg(ctx, msg);
ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class);
verify(ctx).tellNext(captor.capture()); ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class);
TbMsg actualMsg = captor.getValue(); ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class);
assertEquals(customerId, actualMsg.getOriginator()); ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class);
assertEquals(msg.getId(), actualMsg.getId()); ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class);
verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture());
assertEquals(customerId, originatorCaptor.getValue());
} }
@Test @Test
@ -78,17 +87,22 @@ public class TbChangeOriginatorNodeTest {
Asset asset = new Asset(); Asset asset = new Asset();
asset.setCustomerId(customerId); asset.setCustomerId(customerId);
TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}"); RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased());
RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased());
TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
when(ctx.getAssetService()).thenReturn(assetService); when(ctx.getAssetService()).thenReturn(assetService);
when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFuture(asset)); when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFuture(asset));
node.onMsg(ctx, msg); node.onMsg(ctx, msg);
ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class);
verify(ctx).spawn(captor.capture()); ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class);
TbMsg actualMsg = captor.getValue(); ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class);
assertEquals(customerId, actualMsg.getOriginator()); ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class);
assertEquals(msg.getId(), actualMsg.getId()); verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture());
assertEquals(customerId, originatorCaptor.getValue());
} }
@Test @Test
@ -99,7 +113,10 @@ public class TbChangeOriginatorNodeTest {
Asset asset = new Asset(); Asset asset = new Asset();
asset.setCustomerId(customerId); asset.setCustomerId(customerId);
TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}"); RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased());
RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased());
TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L);
when(ctx.getAssetService()).thenReturn(assetService); when(ctx.getAssetService()).thenReturn(assetService);
when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFailedFuture(new IllegalStateException("wrong"))); when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFailedFuture(new IllegalStateException("wrong")));

18
rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java

@ -27,6 +27,8 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -56,8 +58,10 @@ public class TbTransformMsgNodeTest {
metaData.putValue("temp", "7"); metaData.putValue("temp", "7");
String rawJson = "{\"passed\": 5}"; String rawJson = "{\"passed\": 5}";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased());
TbMsg transformedMsg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{new}"); RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased());
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, ruleChainId, ruleNodeId, 0L);
TbMsg transformedMsg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{new}", ruleChainId, ruleNodeId, 0L);
mockJsExecutor(); mockJsExecutor();
when(scriptEngine.executeUpdate(msg)).thenReturn(transformedMsg); when(scriptEngine.executeUpdate(msg)).thenReturn(transformedMsg);
@ -77,8 +81,10 @@ public class TbTransformMsgNodeTest {
metaData.putValue("temp", "7"); metaData.putValue("temp", "7");
String rawJson = "{\"passed\": 5"; String rawJson = "{\"passed\": 5";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased());
TbMsg transformedMsg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{new}"); RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased());
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, ruleChainId, ruleNodeId, 0L);
TbMsg transformedMsg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{new}", ruleChainId, ruleNodeId, 0L);
mockJsExecutor(); mockJsExecutor();
when(scriptEngine.executeUpdate(msg)).thenReturn(transformedMsg); when(scriptEngine.executeUpdate(msg)).thenReturn(transformedMsg);
@ -97,7 +103,9 @@ public class TbTransformMsgNodeTest {
metaData.putValue("temp", "7"); metaData.putValue("temp", "7");
String rawJson = "{\"passed\": 5"; String rawJson = "{\"passed\": 5";
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased());
RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased());
TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, ruleChainId, ruleNodeId, 0L);
mockJsExecutor(); mockJsExecutor();
when(scriptEngine.executeUpdate(msg)).thenThrow(new IllegalStateException("error")); when(scriptEngine.executeUpdate(msg)).thenThrow(new IllegalStateException("error"));

Loading…
Cancel
Save