Browse Source

Merge pull request #8786 from ShvaykaD/feature/filter-nodes-improvements

Filter nodes improvements && fixes for enrichment rule nodes && added TbMsgType enum and enforced use of it in corresponding places.
pull/9044/head
Andrew Shvayka 3 years ago
committed by GitHub
parent
commit
173e229da1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 120
      application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
  2. 4
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
  3. 4
      application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java
  4. 94
      application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java
  5. 25
      application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java
  6. 19
      application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java
  7. 15
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java
  8. 8
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java
  9. 8
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java
  10. 4
      application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java
  11. 3
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  12. 3
      application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
  13. 66
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
  14. 4
      application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java
  15. 3
      application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java
  16. 27
      application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java
  17. 3
      application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
  18. 6
      application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java
  19. 7
      application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java
  20. 28
      application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java
  21. 11
      application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java
  22. 126
      application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java
  23. 3
      application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java
  24. 3
      application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java
  25. 4
      application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java
  26. 5
      application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java
  27. 1
      common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
  28. 26
      common/data/src/main/java/org/thingsboard/server/common/data/EntityFieldsData.java
  29. 15
      common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java
  30. 88
      common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java
  31. 115
      common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java
  32. 13
      common/data/src/main/java/org/thingsboard/server/common/data/msg/TbNodeConnectionType.java
  33. 30
      common/data/src/test/java/org/thingsboard/server/common/data/EntityTypeTest.java
  34. 65
      common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java
  35. 87
      common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java
  36. 192
      common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java
  37. 6
      common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java
  38. 31
      common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapSessionMsgType.java
  39. 27
      common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
  40. 4
      common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/CoapClientContext.java
  41. 4
      common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DefaultCoapClientContext.java
  42. 2
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java
  43. 14
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java
  44. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java
  45. 3
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EmptyNodeConfiguration.java
  46. 3
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java
  47. 34
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
  48. 11
      rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java
  49. 20
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java
  50. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java
  51. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java
  52. 23
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java
  53. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java
  54. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java
  55. 15
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java
  56. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java
  57. 17
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java
  58. 27
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java
  59. 12
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java
  60. 12
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java
  61. 63
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java
  62. 8
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java
  63. 8
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java
  64. 37
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNode.java
  65. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeConfig.java
  66. 18
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java
  67. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeConfiguration.java
  68. 80
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java
  69. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeConfiguration.java
  70. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java
  71. 9
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java
  72. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java
  73. 10
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java
  74. 13
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java
  75. 90
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java
  76. 10
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java
  77. 50
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java
  78. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java
  79. 13
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java
  80. 10
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/AbstractGeofencingNode.java
  81. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java
  82. 8
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java
  83. 14
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java
  84. 10
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java
  85. 13
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java
  86. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java
  87. 16
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java
  88. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java
  89. 20
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java
  90. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDataNode.java
  91. 9
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java
  92. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetMappedDataNode.java
  93. 39
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java
  94. 15
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java
  95. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java
  96. 8
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java
  97. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java
  98. 7
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java
  99. 8
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java
  100. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeConfiguration.java

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

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.actors.ruleChain;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.netty.channel.EventLoopGroup;
@ -35,7 +34,6 @@ import org.thingsboard.rule.engine.api.ScriptEngine;
import org.thingsboard.rule.engine.api.SmsService;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.rule.engine.api.slack.SlackService;
import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
import org.thingsboard.rule.engine.util.TenantIdLoader;
@ -43,7 +41,6 @@ import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.TbActorRef;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType;
@ -62,6 +59,8 @@ 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.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.rule.RuleNode;
@ -115,6 +114,10 @@ import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED;
import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED;
import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_CREATED;
/**
* Created by ashvayka on 19.03.18.
*/
@ -133,7 +136,7 @@ class DefaultTbContext implements TbContext {
@Override
public void tellSuccess(TbMsg msg) {
tellNext(msg, Collections.singleton(TbRelationTypes.SUCCESS), null);
tellNext(msg, Collections.singleton(TbNodeConnectionType.SUCCESS), null);
}
@Override
@ -212,13 +215,13 @@ class DefaultTbContext implements TbContext {
@Override
public void enqueueForTellFailure(TbMsg tbMsg, String failureMessage) {
TopicPartitionInfo tpi = resolvePartition(tbMsg);
enqueueForTellNext(tpi, tbMsg, Collections.singleton(TbRelationTypes.FAILURE), failureMessage, null, null);
enqueueForTellNext(tpi, tbMsg, Collections.singleton(TbNodeConnectionType.FAILURE), failureMessage, null, null);
}
@Override
public void enqueueForTellFailure(TbMsg tbMsg, Throwable th) {
TopicPartitionInfo tpi = resolvePartition(tbMsg);
enqueueForTellNext(tpi, tbMsg, Collections.singleton(TbRelationTypes.FAILURE), getFailureMessage(th), null, null);
enqueueForTellNext(tpi, tbMsg, Collections.singleton(TbNodeConnectionType.FAILURE), getFailureMessage(th), null, null);
}
@Override
@ -316,11 +319,11 @@ class DefaultTbContext implements TbContext {
@Override
public void tellFailure(TbMsg msg, Throwable th) {
if (nodeCtx.getSelf().isDebugMode()) {
mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th);
mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbNodeConnectionType.FAILURE, th);
}
String failureMessage = getFailureMessage(th);
nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getRuleChainId(),
nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE),
nodeCtx.getSelf().getId(), Collections.singleton(TbNodeConnectionType.FAILURE),
msg, failureMessage));
}
@ -343,67 +346,104 @@ class DefaultTbContext implements TbContext {
return TbMsg.transformMsg(origMsg, type, originator, metaData, data);
}
@Override
public TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) {
return newMsg(queueName, type, originator, null, metaData, data);
}
@Override
public TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
return TbMsg.newMsg(queueName, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId());
}
@Override
public TbMsg transformMsg(TbMsg origMsg, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) {
return TbMsg.transformMsg(origMsg, type, originator, metaData, data);
}
@Override
public TbMsg transformMsg(TbMsg origMsg, TbMsgMetaData metaData, String data) {
return TbMsg.transformMsg(origMsg, metaData, data);
}
@Override
public TbMsg transformMsgOriginator(TbMsg origMsg, EntityId originator) {
return TbMsg.transformMsgOriginator(origMsg, originator);
}
@Override
public TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId) {
return entityActionMsg(customer, customer.getId(), ruleNodeId, DataConstants.ENTITY_CREATED);
return entityActionMsg(customer, customer.getId(), ruleNodeId, ENTITY_CREATED);
}
@Override
public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) {
DeviceProfile deviceProfile = null;
if (device.getDeviceProfileId() != null) {
deviceProfile = mainCtx.getDeviceProfileCache().find(device.getDeviceProfileId());
}
return entityActionMsg(device, device.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, deviceProfile);
return entityActionMsg(device, device.getId(), ruleNodeId, ENTITY_CREATED, deviceProfile);
}
@Override
public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) {
AssetProfile assetProfile = null;
if (asset.getAssetProfileId() != null) {
assetProfile = mainCtx.getAssetProfileCache().find(asset.getAssetProfileId());
}
return entityActionMsg(asset, asset.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, assetProfile);
return entityActionMsg(asset, asset.getId(), ruleNodeId, ENTITY_CREATED, assetProfile);
}
@Override
public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action) {
EntityId originator = alarm.getOriginator();
HasRuleEngineProfile profile = getRuleEngineProfile(originator);
return entityActionMsg(alarm, originator, ruleNodeId, action, profile);
}
@Override
public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, TbMsgType actionMsgType) {
EntityId originator = alarm.getOriginator();
HasRuleEngineProfile profile = getRuleEngineProfile(originator);
return entityActionMsg(alarm, originator, ruleNodeId, actionMsgType, profile);
}
private HasRuleEngineProfile getRuleEngineProfile(EntityId originator) {
HasRuleEngineProfile profile = null;
if (EntityType.DEVICE.equals(alarm.getOriginator().getEntityType())) {
DeviceId deviceId = new DeviceId(alarm.getOriginator().getId());
if (EntityType.DEVICE.equals(originator.getEntityType())) {
DeviceId deviceId = new DeviceId(originator.getId());
profile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId);
} else if (EntityType.ASSET.equals(alarm.getOriginator().getEntityType())) {
AssetId assetId = new AssetId(alarm.getOriginator().getId());
} else if (EntityType.ASSET.equals(originator.getEntityType())) {
AssetId assetId = new AssetId(originator.getId());
profile = mainCtx.getAssetProfileCache().get(getTenantId(), assetId);
}
return entityActionMsg(alarm, alarm.getOriginator(), ruleNodeId, action, profile);
return profile;
}
@Override
public TbMsg attributesUpdatedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List<AttributeKvEntry> attributes) {
ObjectNode entityNode = JacksonUtil.newObjectNode();
if (attributes != null) {
attributes.forEach(attributeKvEntry -> JacksonUtil.addKvEntry(entityNode, attributeKvEntry));
}
return attributesActionMsg(originator, ruleNodeId, scope, DataConstants.ATTRIBUTES_UPDATED, JacksonUtil.toString(entityNode));
return attributesActionMsg(originator, ruleNodeId, scope, ATTRIBUTES_UPDATED, JacksonUtil.toString(entityNode));
}
@Override
public TbMsg attributesDeletedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List<String> keys) {
ObjectNode entityNode = JacksonUtil.newObjectNode();
ArrayNode attrsArrayNode = entityNode.putArray("attributes");
if (keys != null) {
keys.forEach(attrsArrayNode::add);
}
return attributesActionMsg(originator, ruleNodeId, scope, DataConstants.ATTRIBUTES_DELETED, JacksonUtil.toString(entityNode));
return attributesActionMsg(originator, ruleNodeId, scope, ATTRIBUTES_DELETED, JacksonUtil.toString(entityNode));
}
private TbMsg attributesActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, String action, String msgData) {
private TbMsg attributesActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, TbMsgType actionMsgType, String msgData) {
TbMsgMetaData tbMsgMetaData = getActionMetaData(ruleNodeId);
tbMsgMetaData.putValue("scope", scope);
HasRuleEngineProfile profile = null;
if (EntityType.DEVICE.equals(originator.getEntityType())) {
DeviceId deviceId = new DeviceId(originator.getId());
profile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId);
} else if (EntityType.ASSET.equals(originator.getEntityType())) {
AssetId assetId = new AssetId(originator.getId());
profile = mainCtx.getAssetProfileCache().get(getTenantId(), assetId);
}
return entityActionMsg(originator, tbMsgMetaData, msgData, action, profile);
HasRuleEngineProfile profile = getRuleEngineProfile(originator);
return entityActionMsg(originator, tbMsgMetaData, msgData, actionMsgType, profile);
}
@Override
@ -411,10 +451,11 @@ class DefaultTbContext implements TbContext {
mainCtx.getClusterService().onEdgeEventUpdate(tenantId, edgeId);
}
public <E, I extends EntityId> TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action) {
return entityActionMsg(entity, id, ruleNodeId, action, null);
public <E, I extends EntityId> TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, TbMsgType actionMsgType) {
return entityActionMsg(entity, id, ruleNodeId, actionMsgType, null);
}
@Deprecated(since = "3.5.2", forRemoval = true)
public <E, I extends EntityId, K extends HasRuleEngineProfile> TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action, K profile) {
try {
return entityActionMsg(id, getActionMetaData(ruleNodeId), JacksonUtil.toString(JacksonUtil.valueToTree(entity)), action, profile);
@ -423,6 +464,7 @@ class DefaultTbContext implements TbContext {
}
}
@Deprecated(since = "3.5.2", forRemoval = true)
private <I extends EntityId, K extends HasRuleEngineProfile> TbMsg entityActionMsg(I id, TbMsgMetaData msgMetaData, String msgData, String action, K profile) {
String defaultQueueName = null;
RuleChainId defaultRuleChainId = null;
@ -433,6 +475,24 @@ class DefaultTbContext implements TbContext {
return TbMsg.newMsg(defaultQueueName, action, id, msgMetaData, msgData, defaultRuleChainId, null);
}
public <E, I extends EntityId, K extends HasRuleEngineProfile> TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, TbMsgType actionMsgType, K profile) {
try {
return entityActionMsg(id, getActionMetaData(ruleNodeId), JacksonUtil.toString(JacksonUtil.valueToTree(entity)), actionMsgType, profile);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Failed to process " + id.getEntityType().name().toLowerCase() + " " + actionMsgType.name() + " msg: " + e);
}
}
private <I extends EntityId, K extends HasRuleEngineProfile> TbMsg entityActionMsg(I id, TbMsgMetaData msgMetaData, String msgData, TbMsgType actionMsgType, K profile) {
String defaultQueueName = null;
RuleChainId defaultRuleChainId = null;
if (profile != null) {
defaultQueueName = profile.getDefaultQueueName();
defaultRuleChainId = profile.getDefaultRuleChainId();
}
return TbMsg.newMsg(defaultQueueName, actionMsgType, id, msgMetaData, msgData, defaultRuleChainId, null);
}
@Override
public RuleNodeId getSelfId() {
return nodeCtx.getSelf().getId();

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

@ -16,7 +16,7 @@
package org.thingsboard.server.actors.ruleChain;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.TbActorCtx;
import org.thingsboard.server.actors.TbActorRef;
@ -307,7 +307,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
int relationsCount = relationsByTypes.size();
if (relationsCount == 0) {
log.trace("[{}][{}][{}] No outbound relations to process", tenantId, entityId, msg.getId());
if (relationTypes.contains(TbRelationTypes.FAILURE)) {
if (relationTypes.contains(TbNodeConnectionType.FAILURE)) {
RuleNodeCtx ruleNodeCtx = nodeActors.get(originatorNodeId);
if (ruleNodeCtx != null) {
msg.getCallback().onFailure(new RuleNodeException(failureMessage, ruleChainName, ruleNodeCtx.getSelf()));

4
application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java

@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.RpcId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.rpc.Rpc;
@ -52,7 +53,6 @@ import org.thingsboard.server.service.security.permission.Operation;
import javax.annotation.Nullable;
import java.util.UUID;
import static org.thingsboard.server.common.data.DataConstants.RPC_DELETED;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END;
@ -239,7 +239,7 @@ public class RpcV2Controller extends AbstractRpcController {
rpcService.deleteRpc(getTenantId(), rpcId);
rpc.setStatus(RpcStatus.DELETED);
TbMsg msg = TbMsg.newMsg(RPC_DELETED, rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc));
TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_DELETED, rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc));
tbClusterService.pushMsgToRuleEngine(getTenantId(), rpc.getDeviceId(), msg, null);
}
}

94
application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java

@ -26,7 +26,6 @@ import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmComment;
@ -38,19 +37,21 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentTrigger;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentTrigger;
import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimitTrigger;
import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionTrigger;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentTrigger;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentTrigger;
import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimitTrigger;
import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionTrigger;
import org.thingsboard.server.dao.audit.AuditLogService;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
@ -63,85 +64,8 @@ public class EntityActionService {
public void pushEntityActionToRuleEngine(EntityId entityId, HasName entity, TenantId tenantId, CustomerId customerId,
ActionType actionType, User user, Object... additionalInfo) {
String msgType = null;
switch (actionType) {
case ADDED:
msgType = DataConstants.ENTITY_CREATED;
break;
case DELETED:
msgType = DataConstants.ENTITY_DELETED;
break;
case UPDATED:
msgType = DataConstants.ENTITY_UPDATED;
break;
case ASSIGNED_TO_CUSTOMER:
msgType = DataConstants.ENTITY_ASSIGNED;
break;
case UNASSIGNED_FROM_CUSTOMER:
msgType = DataConstants.ENTITY_UNASSIGNED;
break;
case ATTRIBUTES_UPDATED:
msgType = DataConstants.ATTRIBUTES_UPDATED;
break;
case ATTRIBUTES_DELETED:
msgType = DataConstants.ATTRIBUTES_DELETED;
break;
case ALARM_ACK:
msgType = DataConstants.ALARM_ACK;
break;
case ALARM_CLEAR:
msgType = DataConstants.ALARM_CLEAR;
break;
case ALARM_ASSIGNED:
msgType = DataConstants.ALARM_ASSIGNED;
break;
case ALARM_UNASSIGNED:
msgType = DataConstants.ALARM_UNASSIGNED;
break;
case ALARM_DELETE:
msgType = DataConstants.ALARM_DELETE;
break;
case ADDED_COMMENT:
msgType = DataConstants.COMMENT_CREATED;
break;
case UPDATED_COMMENT:
msgType = DataConstants.COMMENT_UPDATED;
break;
case ASSIGNED_FROM_TENANT:
msgType = DataConstants.ENTITY_ASSIGNED_FROM_TENANT;
break;
case ASSIGNED_TO_TENANT:
msgType = DataConstants.ENTITY_ASSIGNED_TO_TENANT;
break;
case PROVISION_SUCCESS:
msgType = DataConstants.PROVISION_SUCCESS;
break;
case PROVISION_FAILURE:
msgType = DataConstants.PROVISION_FAILURE;
break;
case TIMESERIES_UPDATED:
msgType = DataConstants.TIMESERIES_UPDATED;
break;
case TIMESERIES_DELETED:
msgType = DataConstants.TIMESERIES_DELETED;
break;
case ASSIGNED_TO_EDGE:
msgType = DataConstants.ENTITY_ASSIGNED_TO_EDGE;
break;
case UNASSIGNED_FROM_EDGE:
msgType = DataConstants.ENTITY_UNASSIGNED_FROM_EDGE;
break;
case RELATION_ADD_OR_UPDATE:
msgType = DataConstants.RELATION_ADD_OR_UPDATE;
break;
case RELATION_DELETED:
msgType = DataConstants.RELATION_DELETED;
break;
case RELATIONS_DELETED:
msgType = DataConstants.RELATIONS_DELETED;
break;
}
if (!StringUtils.isEmpty(msgType)) {
Optional<TbMsgType> msgType = actionType.getRuleEngineMsgType();
if (msgType.isPresent()) {
try {
TbMsgMetaData metaData = new TbMsgMetaData();
if (user != null) {
@ -247,7 +171,7 @@ public class EntityActionService {
if (tenantId != null && !tenantId.isSysTenantId()) {
processNotificationRules(tenantId, entityId, entity, actionType, user, additionalInfo);
}
TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode));
TbMsg tbMsg = TbMsg.newMsg(msgType.get(), entityId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode));
tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, null);
} catch (Exception e) {
log.warn("[{}] Failed to push entity action to rule engine: {}", entityId, actionType, e);

25
application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java

@ -30,8 +30,12 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.rule.engine.api.NodeDefinition;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.rule.engine.api.TbVersionedNode;
import org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode;
import org.thingsboard.rule.engine.filter.TbOriginatorTypeSwitchNode;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType;
@ -194,7 +198,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
scannedComponent.setName(ruleNodeAnnotation.name());
scannedComponent.setScope(ruleNodeAnnotation.scope());
scannedComponent.setClusteringMode(ruleNodeAnnotation.clusteringMode());
NodeDefinition nodeDefinition = prepareNodeDefinition(ruleNodeAnnotation);
NodeDefinition nodeDefinition = prepareNodeDefinition(clazz, ruleNodeAnnotation);
ObjectNode configurationDescriptor = JacksonUtil.newObjectNode();
JsonNode node = JacksonUtil.valueToTree(nodeDefinition);
configurationDescriptor.set("nodeDefinition", node);
@ -221,13 +225,13 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
return scannedComponent;
}
private NodeDefinition prepareNodeDefinition(RuleNode nodeAnnotation) throws Exception {
private NodeDefinition prepareNodeDefinition(Class<?> clazz, RuleNode nodeAnnotation) throws Exception {
NodeDefinition nodeDefinition = new NodeDefinition();
nodeDefinition.setDetails(nodeAnnotation.nodeDetails());
nodeDefinition.setDescription(nodeAnnotation.nodeDescription());
nodeDefinition.setInEnabled(nodeAnnotation.inEnabled());
nodeDefinition.setOutEnabled(nodeAnnotation.outEnabled());
nodeDefinition.setRelationTypes(getRelationTypesWithFailureRelation(nodeAnnotation));
nodeDefinition.setRelationTypes(getRelationTypesWithFailureRelation(clazz, nodeAnnotation));
nodeDefinition.setCustomRelations(nodeAnnotation.customRelations());
nodeDefinition.setRuleChainNode(nodeAnnotation.ruleChainNode());
Class<? extends NodeConfiguration> configClazz = nodeAnnotation.configClazz();
@ -242,10 +246,17 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
return nodeDefinition;
}
private String[] getRelationTypesWithFailureRelation(RuleNode nodeAnnotation) {
private String[] getRelationTypesWithFailureRelation(Class<?> clazz, RuleNode nodeAnnotation) {
List<String> relationTypes = new ArrayList<>(Arrays.asList(nodeAnnotation.relationTypes()));
if (!relationTypes.contains(TbRelationTypes.FAILURE)) {
relationTypes.add(TbRelationTypes.FAILURE);
if (TbOriginatorTypeSwitchNode.class.equals(clazz)) {
relationTypes.addAll(EntityType.NORMAL_NAMES);
}
if (TbMsgTypeSwitchNode.class.equals(clazz)) {
relationTypes.addAll(TbMsgType.NODE_CONNECTIONS);
relationTypes.add(TbNodeConnectionType.OTHER);
}
if (!relationTypes.contains(TbNodeConnectionType.FAILURE)) {
relationTypes.add(TbNodeConnectionType.FAILURE);
}
return relationTypes.toArray(new String[relationTypes.size()]);
}

19
application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java

@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.common.msg.TbMsg;
@ -162,7 +163,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
if (targetProfile.getProfileData().getProvisionConfiguration().getProvisionDeviceSecret().equals(provisionRequestSecret)) {
if (targetDevice != null) {
log.warn("[{}] The device is present and could not be provisioned once more!", targetDevice.getName());
notify(targetDevice, provisionRequest, DataConstants.PROVISION_FAILURE, false);
notify(targetDevice, provisionRequest, TbMsgType.PROVISION_FAILURE, false);
throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name());
} else {
return createDevice(provisionRequest, targetProfile);
@ -190,11 +191,11 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
Optional<AttributeKvEntry> provisionState = attributesService.find(device.getTenantId(), device.getId(),
DataConstants.SERVER_SCOPE, DEVICE_PROVISION_STATE).get();
if (provisionState != null && provisionState.isPresent() && !provisionState.get().getValueAsString().equals(PROVISIONED_STATE)) {
notify(device, provisionRequest, DataConstants.PROVISION_FAILURE, false);
notify(device, provisionRequest, TbMsgType.PROVISION_FAILURE, false);
throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name());
} else {
saveProvisionStateAttribute(device).get();
notify(device, provisionRequest, DataConstants.PROVISION_SUCCESS, true);
notify(device, provisionRequest, TbMsgType.PROVISION_SUCCESS, true);
}
} catch (InterruptedException | ExecutionException e) {
throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name());
@ -206,7 +207,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
return processCreateDevice(provisionRequest, profile);
}
private void notify(Device device, ProvisionRequest provisionRequest, String type, boolean success) {
private void notify(Device device, ProvisionRequest provisionRequest, TbMsgType type, boolean success) {
pushProvisionEventToRuleEngine(provisionRequest, device, type);
logAction(device.getTenantId(), device.getCustomerId(), device, success, provisionRequest);
}
@ -222,14 +223,14 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
clusterService.onDeviceUpdated(savedDevice, null);
saveProvisionStateAttribute(savedDevice).get();
pushDeviceCreatedEventToRuleEngine(savedDevice);
notify(savedDevice, provisionRequest, DataConstants.PROVISION_SUCCESS, true);
notify(savedDevice, provisionRequest, TbMsgType.PROVISION_SUCCESS, true);
return new ProvisionResponse(getDeviceCredentials(savedDevice), ProvisionResponseStatus.SUCCESS);
} catch (Exception e) {
log.warn("[{}] Error during device creation from provision request: [{}]", provisionRequest.getDeviceName(), provisionRequest, e);
Device device = deviceService.findDeviceByTenantIdAndName(profile.getTenantId(), provisionRequest.getDeviceName());
if (device != null) {
notify(device, provisionRequest, DataConstants.PROVISION_FAILURE, false);
notify(device, provisionRequest, TbMsgType.PROVISION_FAILURE, false);
}
throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name());
}
@ -253,7 +254,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
return deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), device.getId());
}
private void pushProvisionEventToRuleEngine(ProvisionRequest request, Device device, String type) {
private void pushProvisionEventToRuleEngine(ProvisionRequest request, Device device, TbMsgType type) {
try {
JsonNode entityNode = JacksonUtil.valueToTree(request);
TbMsg msg = TbMsg.newMsg(type, device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.toString(entityNode));
@ -266,10 +267,10 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
private void pushDeviceCreatedEventToRuleEngine(Device device) {
try {
ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device);
TbMsg msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode));
TbMsg msg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode));
sendToRuleEngine(device.getTenantId(), msg, null);
} catch (JsonProcessingException | IllegalArgumentException e) {
log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), DataConstants.ENTITY_CREATED, e);
log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), TbMsgType.ENTITY_CREATED.name(), e);
}
}

15
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java

@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.BooleanDataEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -71,10 +72,6 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import static org.thingsboard.server.common.data.DataConstants.CONNECT_EVENT;
import static org.thingsboard.server.common.data.DataConstants.DISCONNECT_EVENT;
import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE;
@Service
@Slf4j
@ConditionalOnProperty(prefix = "edges", value = "enabled", havingValue = "true")
@ -278,7 +275,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true);
long lastConnectTs = System.currentTimeMillis();
save(edgeId, DefaultDeviceStateService.LAST_CONNECT_TIME, lastConnectTs);
pushRuleEngineMessage(edgeGrpcSession.getEdge().getTenantId(), edgeId, lastConnectTs, CONNECT_EVENT);
pushRuleEngineMessage(edgeGrpcSession.getEdge().getTenantId(), edgeId, lastConnectTs, TbMsgType.CONNECT_EVENT);
cancelScheduleEdgeEventsCheck(edgeId);
scheduleEdgeEventsCheck(edgeGrpcSession);
}
@ -398,7 +395,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false);
long lastDisconnectTs = System.currentTimeMillis();
save(edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, lastDisconnectTs);
pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edgeId, lastDisconnectTs, DISCONNECT_EVENT);
pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edgeId, lastDisconnectTs, TbMsgType.DISCONNECT_EVENT);
cancelScheduleEdgeEventsCheck(edgeId);
} else {
log.debug("[{}] edge session [{}] is not available anymore, nothing to remove. most probably this session is already outdated!", edgeId, sessionId);
@ -451,10 +448,10 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
}
}
private void pushRuleEngineMessage(TenantId tenantId, EdgeId edgeId, long ts, String msgType) {
private void pushRuleEngineMessage(TenantId tenantId, EdgeId edgeId, long ts, TbMsgType msgType) {
try {
ObjectNode edgeState = JacksonUtil.newObjectNode();
if (msgType.equals(CONNECT_EVENT)) {
if (msgType.equals(TbMsgType.CONNECT_EVENT)) {
edgeState.put(DefaultDeviceStateService.ACTIVITY_STATE, true);
edgeState.put(DefaultDeviceStateService.LAST_CONNECT_TIME, ts);
} else {
@ -464,7 +461,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
String data = JacksonUtil.toString(edgeState);
TbMsgMetaData md = new TbMsgMetaData();
if (!persistToTelemetry) {
md.putValue(DataConstants.SCOPE, SERVER_SCOPE);
md.putValue(DataConstants.SCOPE, DataConstants.SERVER_SCOPE);
}
TbMsg tbMsg = TbMsg.newMsg(msgType, edgeId, md, TbMsgDataType.JSON, data);
clusterService.pushMsgToRuleEngine(tenantId, edgeId, tbMsg, null);

8
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java

@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rpc.RpcError;
@ -46,7 +47,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.DeviceCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.v1.DeviceCredentialsUpdateMsg;
@ -124,7 +124,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
try {
Device device = deviceService.findDeviceById(tenantId, deviceId);
ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device);
TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, device.getCustomerId(),
TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceId, device.getCustomerId(),
getActionTbMsgMetaData(edge, device.getCustomerId()), TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode));
tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() {
@Override
@ -138,7 +138,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
}
});
} catch (JsonProcessingException | IllegalArgumentException e) {
log.warn("[{}] Failed to push device action to rule engine: {}", deviceId, DataConstants.ENTITY_CREATED, e);
log.warn("[{}] Failed to push device action to rule engine: {}", deviceId, TbMsgType.ENTITY_CREATED.name(), e);
}
}
@ -216,7 +216,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
ObjectNode data = JacksonUtil.newObjectNode();
data.put("method", deviceRpcCallMsg.getRequestMsg().getMethod());
data.put("params", deviceRpcCallMsg.getRequestMsg().getParams());
TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, null, metaData,
TbMsg tbMsg = TbMsg.newMsg(TbMsgType.TO_SERVER_RPC_REQUEST, deviceId, null, metaData,
TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(data));
tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() {
@Override

8
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java

@ -50,11 +50,11 @@ import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.common.transport.util.JsonUtils;
import org.thingsboard.server.dao.model.ModelConstants;
@ -184,7 +184,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
metaData.putValue("ts", tsKv.getTs() + "");
var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.POST_TELEMETRY_REQUEST, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
@ -228,7 +228,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
SettableFuture<Void> futureToSet = SettableFuture.create();
JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
@ -257,7 +257,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
@Override
public void onSuccess(@Nullable Void tmp) {
var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), DataConstants.ATTRIBUTES_UPDATED, entityId,
TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.ATTRIBUTES_UPDATED, entityId,
customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override

4
application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java

@ -21,7 +21,6 @@ import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName;
@ -40,6 +39,7 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.rule.RuleChain;
@ -286,7 +286,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
String data = JacksonUtil.toString(JacksonUtil.valueToTree(assignedDevice));
if (data != null) {
TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(),
TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(),
assignedDevice.getCustomerId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data);
tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null);
}

3
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -114,13 +114,14 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE;
@Service
@Profile("install")
@Slf4j
public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
public static final String CUSTOMER_CRED = "customer";
public static final String DEFAULT_DEVICE_TYPE = "default";
public static final String ACTIVITY_STATE = "active";
@Autowired

3
application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java

@ -47,6 +47,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.data.page.PageLink;
@ -502,7 +503,7 @@ public class DefaultDataUpdateService implements DataUpdateService {
md.getNodes().add(ruleNode);
md.setFirstNodeIndex(newIdx);
md.addConnectionInfo(newIdx, oldIdx, "Success");
md.addConnectionInfo(newIdx, oldIdx, TbNodeConnectionType.SUCCESS);
ruleChainService.saveRuleChainMetaData(tenant.getId(), md, Function.identity());
}
} catch (Exception e) {

66
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java

@ -32,10 +32,10 @@ import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasRuleEngineProfile;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AssetId;
@ -178,15 +178,8 @@ public class DefaultTbClusterService implements TbClusterService {
return;
}
} else {
if (entityId.getEntityType().equals(EntityType.DEVICE)) {
tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceId(entityId.getId())));
} else if (entityId.getEntityType().equals(EntityType.DEVICE_PROFILE)) {
tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId())));
} else if (entityId.getEntityType().equals(EntityType.ASSET)) {
tbMsg = transformMsg(tbMsg, assetProfileCache.get(tenantId, new AssetId(entityId.getId())));
} else if (entityId.getEntityType().equals(EntityType.ASSET_PROFILE)) {
tbMsg = transformMsg(tbMsg, assetProfileCache.get(tenantId, new AssetProfileId(entityId.getId())));
}
HasRuleEngineProfile ruleEngineProfile = getRuleEngineProfileForEntityOrElseNull(tenantId, entityId);
tbMsg = transformMsg(tbMsg, ruleEngineProfile);
}
TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueName(), tenantId, entityId);
log.trace("PUSHING msg: {} to:{}", tbMsg, tpi);
@ -198,34 +191,33 @@ public class DefaultTbClusterService implements TbClusterService {
toRuleEngineMsgs.incrementAndGet();
}
private TbMsg transformMsg(TbMsg tbMsg, DeviceProfile deviceProfile) {
if (deviceProfile != null) {
RuleChainId targetRuleChainId = deviceProfile.getDefaultRuleChainId();
String targetQueueName = deviceProfile.getDefaultQueueName();
tbMsg = transformMsg(tbMsg, targetRuleChainId, targetQueueName);
}
return tbMsg;
}
private TbMsg transformMsg(TbMsg tbMsg, AssetProfile assetProfile) {
if (assetProfile != null) {
RuleChainId targetRuleChainId = assetProfile.getDefaultRuleChainId();
String targetQueueName = assetProfile.getDefaultQueueName();
tbMsg = transformMsg(tbMsg, targetRuleChainId, targetQueueName);
private HasRuleEngineProfile getRuleEngineProfileForEntityOrElseNull(TenantId tenantId, EntityId entityId) {
if (entityId.getEntityType().equals(EntityType.DEVICE)) {
return deviceProfileCache.get(tenantId, new DeviceId(entityId.getId()));
} else if (entityId.getEntityType().equals(EntityType.DEVICE_PROFILE)) {
return deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId()));
} else if (entityId.getEntityType().equals(EntityType.ASSET)) {
return assetProfileCache.get(tenantId, new AssetId(entityId.getId()));
} else if (entityId.getEntityType().equals(EntityType.ASSET_PROFILE)) {
return assetProfileCache.get(tenantId, new AssetProfileId(entityId.getId()));
}
return tbMsg;
}
private TbMsg transformMsg(TbMsg tbMsg, RuleChainId targetRuleChainId, String targetQueueName) {
boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId());
boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName());
if (isRuleChainTransform && isQueueTransform) {
tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName);
} else if (isRuleChainTransform) {
tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId);
} else if (isQueueTransform) {
tbMsg = TbMsg.transformMsg(tbMsg, targetQueueName);
return null;
}
private TbMsg transformMsg(TbMsg tbMsg, HasRuleEngineProfile ruleEngineProfile) {
if (ruleEngineProfile != null) {
RuleChainId targetRuleChainId = ruleEngineProfile.getDefaultRuleChainId();
String targetQueueName = ruleEngineProfile.getDefaultQueueName();
boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId());
boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName());
if (isRuleChainTransform && isQueueTransform) {
tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName);
} else if (isRuleChainTransform) {
tbMsg = TbMsg.transformMsgRuleChainId(tbMsg, targetRuleChainId);
} else if (isQueueTransform) {
tbMsg = TbMsg.transformMsgQueueName(tbMsg, targetQueueName);
}
}
return tbMsg;
}

4
application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.service.rpc;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -27,6 +26,7 @@ import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.rpc.RpcError;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
@ -182,7 +182,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
entityNode.put(DataConstants.ADDITIONAL_INFO, msg.getAdditionalInfo());
try {
TbMsg tbMsg = TbMsg.newMsg(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE, msg.getDeviceId(), Optional.ofNullable(currentUser).map(User::getCustomerId).orElse(null), metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode));
TbMsg tbMsg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, msg.getDeviceId(), Optional.ofNullable(currentUser).map(User::getCustomerId).orElse(null), metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode));
clusterService.pushMsgToRuleEngine(msg.getTenantId(), msg.getDeviceId(), tbMsg, null);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);

3
application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java

@ -24,6 +24,7 @@ import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.RpcId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.rpc.Rpc;
@ -62,7 +63,7 @@ public class TbRpcService {
}
private void pushRpcMsgToRuleEngine(TenantId tenantId, Rpc rpc) {
TbMsg msg = TbMsg.newMsg("RPC_" + rpc.getStatus().name(), rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc));
TbMsg msg = TbMsg.newMsg(TbMsgType.valueOf("RPC_" + rpc.getStatus().name()), rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc));
tbClusterService.pushMsgToRuleEngine(tenantId, rpc.getDeviceId(), msg, null);
}

27
application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java

@ -36,7 +36,6 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.ApiUsageRecordKey;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceIdInfo;
import org.thingsboard.server.common.data.EntityType;
@ -51,6 +50,8 @@ import org.thingsboard.server.common.data.kv.BooleanDataEntry;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityTrigger;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.data.query.EntityData;
@ -63,7 +64,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityTrigger;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
@ -102,10 +102,7 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.DataConstants.ACTIVITY_EVENT;
import static org.thingsboard.server.common.data.DataConstants.CONNECT_EVENT;
import static org.thingsboard.server.common.data.DataConstants.DISCONNECT_EVENT;
import static org.thingsboard.server.common.data.DataConstants.INACTIVITY_EVENT;
import static org.thingsboard.server.common.data.DataConstants.SCOPE;
import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE;
/**
@ -229,7 +226,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
long ts = System.currentTimeMillis();
stateData.getState().setLastConnectTime(ts);
save(deviceId, LAST_CONNECT_TIME, ts);
pushRuleEngineMessage(stateData, CONNECT_EVENT);
pushRuleEngineMessage(stateData, TbMsgType.CONNECT_EVENT);
checkAndUpdateState(deviceId, stateData);
}
@ -271,7 +268,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
long ts = System.currentTimeMillis();
stateData.getState().setLastDisconnectTime(ts);
save(deviceId, LAST_DISCONNECT_TIME, ts);
pushRuleEngineMessage(stateData, DISCONNECT_EVENT);
pushRuleEngineMessage(stateData, TbMsgType.DISCONNECT_EVENT);
}
@Override
@ -533,7 +530,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
private void onDeviceActivityStatusChange(DeviceId deviceId, boolean active, DeviceStateData stateData) {
save(deviceId, ACTIVITY_STATE, active);
pushRuleEngineMessage(stateData, active ? ACTIVITY_EVENT : INACTIVITY_EVENT);
pushRuleEngineMessage(stateData, active ? TbMsgType.ACTIVITY_EVENT : TbMsgType.INACTIVITY_EVENT);
TbMsgMetaData metaData = stateData.getMetaData();
notificationRuleProcessor.process(DeviceActivityTrigger.builder()
.tenantId(stateData.getTenantId()).customerId(stateData.getCustomerId())
@ -580,7 +577,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
ListenableFuture<List<TsKvEntry>> tsData = tsService.findLatest(TenantId.SYS_TENANT_ID, device.getId(), PERSISTENT_ATTRIBUTES);
future = Futures.transform(tsData, extractDeviceStateData(device), deviceStateExecutor);
} else {
ListenableFuture<List<AttributeKvEntry>> attrData = attributesService.find(TenantId.SYS_TENANT_ID, device.getId(), DataConstants.SERVER_SCOPE, PERSISTENT_ATTRIBUTES);
ListenableFuture<List<AttributeKvEntry>> attrData = attributesService.find(TenantId.SYS_TENANT_ID, device.getId(), SERVER_SCOPE, PERSISTENT_ATTRIBUTES);
future = Futures.transform(attrData, extractDeviceStateData(device), deviceStateExecutor);
}
return transformInactivityTimeout(future);
@ -771,11 +768,11 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
return defaultValue;
}
private void pushRuleEngineMessage(DeviceStateData stateData, String msgType) {
private void pushRuleEngineMessage(DeviceStateData stateData, TbMsgType msgType) {
DeviceState state = stateData.getState();
try {
String data;
if (msgType.equals(CONNECT_EVENT)) {
if (msgType.equals(TbMsgType.CONNECT_EVENT)) {
ObjectNode stateNode = JacksonUtil.convertValue(state, ObjectNode.class);
stateNode.remove(ACTIVITY_STATE);
data = JacksonUtil.toString(stateNode);
@ -784,7 +781,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
}
TbMsgMetaData md = stateData.getMetaData().copy();
if (!persistToTelemetry) {
md.putValue(DataConstants.SCOPE, SERVER_SCOPE);
md.putValue(SCOPE, SERVER_SCOPE);
}
TbMsg tbMsg = TbMsg.newMsg(msgType, stateData.getDeviceId(), stateData.getCustomerId(), md, TbMsgDataType.JSON, data);
clusterService.pushMsgToRuleEngine(stateData.getTenantId(), stateData.getDeviceId(), tbMsg, null);
@ -800,7 +797,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry(key, value))),
new TelemetrySaveCallback<>(deviceId, key, value));
} else {
tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value));
tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value));
}
}
@ -811,7 +808,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new BooleanDataEntry(key, value))),
new TelemetrySaveCallback<>(deviceId, key, value));
} else {
tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value));
tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value));
}
}

3
application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java

@ -53,6 +53,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUtil;
import org.thingsboard.server.common.data.page.PageData;
@ -346,7 +347,7 @@ public class DefaultTransportApiService implements TransportApiService {
DeviceId deviceId = device.getId();
JsonNode entityNode = JacksonUtil.valueToTree(device);
TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode));
TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode));
tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, null);
} else {
JsonNode deviceAdditionalInfo = device.getAdditionalInfo();

6
application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java

@ -25,13 +25,13 @@ import org.thingsboard.server.common.data.event.EventType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.dao.rule.RuleChainService;
import java.io.IOException;
import java.util.function.Predicate;
/**
@ -82,8 +82,8 @@ public abstract class AbstractRuleEngineControllerTest extends AbstractControlle
}
}
protected Predicate<EventInfo> filterByCustomEvent() {
return event -> event.getBody().get("msgType").textValue().equals("CUSTOM");
protected Predicate<EventInfo> filterByPostTelemetryEventType() {
return event -> event.getBody().get("msgType").textValue().equals(TbMsgType.POST_TELEMETRY_REQUEST.name());
}
}

7
application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java

@ -43,6 +43,7 @@ import org.springframework.test.web.servlet.ResultActions;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EntityViewInfo;
import org.thingsboard.server.common.data.StringUtils;
@ -253,7 +254,7 @@ public class EntityViewControllerTest extends AbstractControllerTest {
doGet("/api/entityView/" + entityIdStr)
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Entity view",entityIdStr))));
.andExpect(statusReason(containsString(msgErrorNoFound(EntityType.ENTITY_VIEW.getNormalName(), entityIdStr))));
}
@Test
@ -425,12 +426,12 @@ public class EntityViewControllerTest extends AbstractControllerTest {
testNotifyEntityBroadcastEntityStateChangeEventMany(new EntityView(), new EntityView(),
tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
ActionType.ADDED, ActionType.ADDED, cntEntity, 0, cntEntity*2, 0);
ActionType.ADDED, ActionType.ADDED, cntEntity, 0, cntEntity * 2, 0);
testNotifyEntityBroadcastEntityStateChangeEventMany(new EntityView(), new EntityView(),
tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
ActionType.ASSIGNED_TO_CUSTOMER, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity,
cntEntity*2, 3);
cntEntity * 2, 3);
}
@Test

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

@ -27,7 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.util.ReflectionTestUtils;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration;
import org.thingsboard.rule.engine.metadata.FetchTo;
import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.rule.engine.metadata.TbGetAttributesNode;
import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
import org.thingsboard.server.actors.ActorSystemContext;
@ -39,6 +39,8 @@ import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.event.Event;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChain;
@ -142,7 +144,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
ruleNode1.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration();
configuration1.setFetchTo(FetchTo.METADATA);
configuration1.setFetchTo(TbMsgSource.METADATA);
configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1"));
ruleNode1.setConfiguration(JacksonUtil.valueToTree(configuration1));
@ -152,14 +154,14 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
ruleNode2.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration();
configuration2.setFetchTo(FetchTo.METADATA);
configuration2.setFetchTo(TbMsgSource.METADATA);
configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2"));
ruleNode2.setConfiguration(JacksonUtil.valueToTree(configuration2));
metaData.setNodes(Arrays.asList(ruleNode1, ruleNode2));
metaData.setFirstNodeIndex(0);
metaData.addConnectionInfo(0, 1, "Success");
metaData.addConnectionInfo(0, 1, TbNodeConnectionType.SUCCESS);
metaData = saveRuleChainMetaData(metaData);
Assert.assertNotNull(metaData);
@ -179,14 +181,14 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class);
Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true);
TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback);
TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback);
QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null);
// Pushing Message to the system
actorSystem.tell(qMsg);
Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess();
PageData<EventInfo> eventsPage = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000);
List<EventInfo> events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
List<EventInfo> events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList());
Assert.assertEquals(2, events.size());
EventInfo inEvent = events.stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.IN)).findFirst().get();
@ -203,7 +205,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
RuleNode lastRuleNode = metaData.getNodes().stream().filter(node -> !node.getId().equals(finalRuleChain.getFirstRuleNodeId())).findFirst().get();
eventsPage = getDebugEvents(savedTenant.getId(), lastRuleNode.getId(), 1000);
events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList());
Assert.assertEquals(2, events.size());
@ -248,7 +250,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
ruleNode1.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration();
configuration1.setFetchTo(FetchTo.METADATA);
configuration1.setFetchTo(TbMsgSource.METADATA);
configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1"));
ruleNode1.setConfiguration(JacksonUtil.valueToTree(configuration1));
@ -265,7 +267,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
NodeConnectionInfo connection = new NodeConnectionInfo();
connection.setFromIndex(0);
connection.setToIndex(1);
connection.setType("Success");
connection.setType(TbNodeConnectionType.SUCCESS);
rootMetaData.setConnections(Collections.singletonList(connection));
rootMetaData = saveRuleChainMetaData(rootMetaData);
Assert.assertNotNull(rootMetaData);
@ -282,7 +284,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
ruleNode2.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration();
configuration2.setFetchTo(FetchTo.METADATA);
configuration2.setFetchTo(TbMsgSource.METADATA);
configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2"));
ruleNode2.setConfiguration(JacksonUtil.valueToTree(configuration2));
@ -304,7 +306,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class);
Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true);
TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback);
TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback);
QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null);
// Pushing Message to the system
actorSystem.tell(qMsg);
@ -312,7 +314,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess();
PageData<EventInfo> eventsPage = getDebugEvents(savedTenant.getId(), rootRuleChain.getFirstRuleNodeId(), 1000);
List<EventInfo> events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
List<EventInfo> events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList());
Assert.assertEquals(2, events.size());
@ -330,7 +332,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
RuleNode lastRuleNode = secondaryMetaData.getNodes().stream().filter(node -> !node.getId().equals(finalRuleChain.getFirstRuleNodeId())).findFirst().get();
eventsPage = getDebugEvents(savedTenant.getId(), lastRuleNode.getId(), 1000);
events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList());
Assert.assertEquals(2, events.size());

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

@ -24,7 +24,7 @@ import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.metadata.FetchTo;
import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.rule.engine.metadata.TbGetAttributesNode;
import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
import org.thingsboard.server.actors.ActorSystemContext;
@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.EventInfo;
import org.thingsboard.server.common.data.event.EventType;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
@ -97,7 +98,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
ruleNode.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
ruleNode.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration = new TbGetAttributesNodeConfiguration();
configuration.setFetchTo(FetchTo.METADATA);
configuration.setFetchTo(TbMsgSource.METADATA);
configuration.setServerAttributeNames(Collections.singletonList("serverAttributeKey"));
ruleNode.setConfiguration(JacksonUtil.valueToTree(configuration));
@ -139,7 +140,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
log.warn("attr updated");
TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class);
Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true);
TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback);
TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback);
QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(tenantId, tbMsg, null, null);
// Pushing Message to the system
log.warn("before tell tbMsgCallback");
@ -147,12 +148,12 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
log.warn("awaiting tbMsgCallback");
Mockito.verify(tbMsgCallback, Mockito.timeout(TimeUnit.SECONDS.toMillis(TIMEOUT))).onSuccess();
log.warn("awaiting events");
List<EventInfo> events = Awaitility.await("get debug by custom event")
List<EventInfo> events = Awaitility.await("get debug by post telemetry event")
.pollInterval(10, MILLISECONDS)
.atMost(TIMEOUT, TimeUnit.SECONDS)
.until(() -> {
List<EventInfo> debugEvents = getDebugEvents(tenantId, ruleChainFinal.getFirstRuleNodeId(), 1000)
.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList());
log.warn("filtered debug events [{}]", debugEvents.size());
debugEvents.forEach((e) -> log.warn("event: {}", e));
return debugEvents;

126
application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java

@ -24,9 +24,11 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
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.msg.TbMsgType;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
@ -45,6 +47,8 @@ import java.util.UUID;
@RunWith(MockitoJUnitRunner.class)
public class RuleChainMsgConstructorTest {
private static final String RPC_CONNECTION_TYPE = "RPC";
private RuleChainMsgConstructor constructor;
private TenantId tenantId;
@ -99,19 +103,19 @@ public class RuleChainMsgConstructorTest {
Assert.assertEquals("Connections count incorrect!", 13, ruleChainMetadataUpdateMsg.getConnectionsCount());
Assert.assertEquals("Rule chain connections count incorrect!", 0, ruleChainMetadataUpdateMsg.getRuleChainConnectionsCount());
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 6, "Success"), ruleChainMetadataUpdateMsg.getConnections(0));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 10, "Success"), ruleChainMetadataUpdateMsg.getConnections(1));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(2));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 11, "Success"), ruleChainMetadataUpdateMsg.getConnections(3));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 11, "Success"), ruleChainMetadataUpdateMsg.getConnections(4));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 11, "Attributes Updated"), ruleChainMetadataUpdateMsg.getConnections(5));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 7, "RPC Request from Device"), ruleChainMetadataUpdateMsg.getConnections(6));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 4, "Post telemetry"), ruleChainMetadataUpdateMsg.getConnections(7));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 5, "Post attributes"), ruleChainMetadataUpdateMsg.getConnections(8));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 8, "Other"), ruleChainMetadataUpdateMsg.getConnections(9));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 9, "RPC Request to Device"), ruleChainMetadataUpdateMsg.getConnections(10));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(7, 11, "Success"), ruleChainMetadataUpdateMsg.getConnections(11));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(10, 9, "RPC"), ruleChainMetadataUpdateMsg.getConnections(12));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 6, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(0));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 10, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(1));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 0, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(2));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 11, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(3));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 11, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(4));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 11, TbMsgType.ATTRIBUTES_UPDATED.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(5));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 7, TbMsgType.TO_SERVER_RPC_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(6));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 4, TbMsgType.POST_TELEMETRY_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(7));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 5, TbMsgType.POST_ATTRIBUTES_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(8));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 8, TbNodeConnectionType.OTHER), ruleChainMetadataUpdateMsg.getConnections(9));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 9, TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(10));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(7, 11, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(11));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(10, 9, RPC_CONNECTION_TYPE), ruleChainMetadataUpdateMsg.getConnections(12));
}
@Test
@ -130,20 +134,20 @@ public class RuleChainMsgConstructorTest {
Assert.assertEquals("Connections count incorrect!", 10, ruleChainMetadataUpdateMsg.getConnectionsCount());
Assert.assertEquals("Rule chain connections count incorrect!", 1, ruleChainMetadataUpdateMsg.getRuleChainConnectionsCount());
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(2, 5, "Success"), ruleChainMetadataUpdateMsg.getConnections(0));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 9, "Success"), ruleChainMetadataUpdateMsg.getConnections(1));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 9, "Success"), ruleChainMetadataUpdateMsg.getConnections(2));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 9, "Attributes Updated"), ruleChainMetadataUpdateMsg.getConnections(3));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 6, "RPC Request from Device"), ruleChainMetadataUpdateMsg.getConnections(4));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 3, "Post telemetry"), ruleChainMetadataUpdateMsg.getConnections(5));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 4, "Post attributes"), ruleChainMetadataUpdateMsg.getConnections(6));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 7, "Other"), ruleChainMetadataUpdateMsg.getConnections(7));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 8, "RPC Request to Device"), ruleChainMetadataUpdateMsg.getConnections(8));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 9, "Success"), ruleChainMetadataUpdateMsg.getConnections(9));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(2, 5, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(0));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 9, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(1));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 9, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(2));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 9, TbMsgType.ATTRIBUTES_UPDATED.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(3));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 6, TbMsgType.TO_SERVER_RPC_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(4));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 3, TbMsgType.POST_TELEMETRY_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(5));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 4, TbMsgType.POST_ATTRIBUTES_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(6));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 7, TbNodeConnectionType.OTHER), ruleChainMetadataUpdateMsg.getConnections(7));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 8, TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(8));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 9, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(9));
RuleChainConnectionInfoProto ruleChainConnection = ruleChainMetadataUpdateMsg.getRuleChainConnections(0);
Assert.assertEquals("From index incorrect!", 2, ruleChainConnection.getFromIndex());
Assert.assertEquals("Type index incorrect!", "Success", ruleChainConnection.getType());
Assert.assertEquals("Type index incorrect!", TbNodeConnectionType.SUCCESS, ruleChainConnection.getType());
Assert.assertEquals("Additional info incorrect!",
"{\"description\":\"\",\"layoutX\":477,\"layoutY\":560,\"ruleChainNodeId\":\"rule-chain-node-UNDEFINED\"}",
ruleChainConnection.getAdditionalInfo());
@ -172,20 +176,20 @@ public class RuleChainMsgConstructorTest {
Assert.assertEquals("Connections count incorrect!", 10, ruleChainMetadataUpdateMsg.getConnectionsCount());
Assert.assertEquals("Rule chain connections count incorrect!", 1, ruleChainMetadataUpdateMsg.getRuleChainConnectionsCount());
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(0));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 0, "Attributes Updated"), ruleChainMetadataUpdateMsg.getConnections(1));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 3, "RPC Request from Device"), ruleChainMetadataUpdateMsg.getConnections(2));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 6, "Post telemetry"), ruleChainMetadataUpdateMsg.getConnections(3));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 5, "Post attributes"), ruleChainMetadataUpdateMsg.getConnections(4));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 2, "Other"), ruleChainMetadataUpdateMsg.getConnections(5));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 1, "RPC Request to Device"), ruleChainMetadataUpdateMsg.getConnections(6));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(7));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(8));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(7, 4, "Success"), ruleChainMetadataUpdateMsg.getConnections(9));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 0, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(0));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 0, TbMsgType.ATTRIBUTES_UPDATED.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(1));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 3, TbMsgType.TO_SERVER_RPC_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(2));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 6, TbMsgType.POST_TELEMETRY_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(3));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 5, TbMsgType.POST_ATTRIBUTES_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(4));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 2, TbNodeConnectionType.OTHER), ruleChainMetadataUpdateMsg.getConnections(5));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 1, TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(6));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 0, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(7));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 0, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(8));
compareNodeConnectionInfoAndProto(createNodeConnectionInfo(7, 4, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(9));
RuleChainConnectionInfoProto ruleChainConnection = ruleChainMetadataUpdateMsg.getRuleChainConnections(0);
Assert.assertEquals("From index incorrect!", 7, ruleChainConnection.getFromIndex());
Assert.assertEquals("Type index incorrect!", "Success", ruleChainConnection.getType());
Assert.assertEquals("Type index incorrect!", TbNodeConnectionType.SUCCESS, ruleChainConnection.getType());
Assert.assertEquals("Additional info incorrect!",
"{\"description\":\"\",\"layoutX\":477,\"layoutY\":560,\"ruleChainNodeId\":\"rule-chain-node-UNDEFINED\"}",
ruleChainConnection.getAdditionalInfo());
@ -225,19 +229,19 @@ public class RuleChainMsgConstructorTest {
private List<NodeConnectionInfo> createConnections() {
List<NodeConnectionInfo> result = new ArrayList<>();
result.add(createNodeConnectionInfo(3, 6, "Success"));
result.add(createNodeConnectionInfo(3, 10, "Success"));
result.add(createNodeConnectionInfo(3, 0, "Success"));
result.add(createNodeConnectionInfo(4, 11, "Success"));
result.add(createNodeConnectionInfo(5, 11, "Success"));
result.add(createNodeConnectionInfo(6, 11, "Attributes Updated"));
result.add(createNodeConnectionInfo(6, 7, "RPC Request from Device"));
result.add(createNodeConnectionInfo(6, 4, "Post telemetry"));
result.add(createNodeConnectionInfo(6, 5, "Post attributes"));
result.add(createNodeConnectionInfo(6, 8, "Other"));
result.add(createNodeConnectionInfo(6, 9, "RPC Request to Device"));
result.add(createNodeConnectionInfo(7, 11, "Success"));
result.add(createNodeConnectionInfo(10, 9, "RPC"));
result.add(createNodeConnectionInfo(3, 6, TbNodeConnectionType.SUCCESS));
result.add(createNodeConnectionInfo(3, 10, TbNodeConnectionType.SUCCESS));
result.add(createNodeConnectionInfo(3, 0, TbNodeConnectionType.SUCCESS));
result.add(createNodeConnectionInfo(4, 11, TbNodeConnectionType.SUCCESS));
result.add(createNodeConnectionInfo(5, 11, TbNodeConnectionType.SUCCESS));
result.add(createNodeConnectionInfo(6, 11, TbMsgType.ATTRIBUTES_UPDATED.getRuleNodeConnection()));
result.add(createNodeConnectionInfo(6, 7, TbMsgType.TO_SERVER_RPC_REQUEST.getRuleNodeConnection()));
result.add(createNodeConnectionInfo(6, 4, TbMsgType.POST_TELEMETRY_REQUEST.getRuleNodeConnection()));
result.add(createNodeConnectionInfo(6, 5, TbMsgType.POST_ATTRIBUTES_REQUEST.getRuleNodeConnection()));
result.add(createNodeConnectionInfo(6, 8, TbNodeConnectionType.OTHER));
result.add(createNodeConnectionInfo(6, 9, TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.getRuleNodeConnection()));
result.add(createNodeConnectionInfo(7, 11, TbNodeConnectionType.SUCCESS));
result.add(createNodeConnectionInfo(10, 9, RPC_CONNECTION_TYPE));
return result;
}
@ -280,19 +284,19 @@ public class RuleChainMsgConstructorTest {
private List<NodeConnectionInfo> createConnectionsInDifferentOrder() {
List<NodeConnectionInfo> result = new ArrayList<>();
result.add(createNodeConnectionInfo(0, 2, "RPC"));
result.add(createNodeConnectionInfo(4, 1, "Success"));
result.add(createNodeConnectionInfo(5, 1, "Attributes Updated"));
result.add(createNodeConnectionInfo(5, 4, "RPC Request from Device"));
result.add(createNodeConnectionInfo(5, 7, "Post telemetry"));
result.add(createNodeConnectionInfo(5, 6, "Post attributes"));
result.add(createNodeConnectionInfo(5, 3, "Other"));
result.add(createNodeConnectionInfo(5, 2, "RPC Request to Device"));
result.add(createNodeConnectionInfo(6, 1, "Success"));
result.add(createNodeConnectionInfo(7, 1, "Success"));
result.add(createNodeConnectionInfo(8, 11, "Success"));
result.add(createNodeConnectionInfo(8, 5, "Success"));
result.add(createNodeConnectionInfo(8, 0, "Success"));
result.add(createNodeConnectionInfo(0, 2, RPC_CONNECTION_TYPE));
result.add(createNodeConnectionInfo(4, 1, TbNodeConnectionType.SUCCESS));
result.add(createNodeConnectionInfo(5, 1, TbMsgType.ATTRIBUTES_UPDATED.getRuleNodeConnection()));
result.add(createNodeConnectionInfo(5, 4, TbMsgType.TO_SERVER_RPC_REQUEST.getRuleNodeConnection()));
result.add(createNodeConnectionInfo(5, 7, TbMsgType.POST_TELEMETRY_REQUEST.getRuleNodeConnection()));
result.add(createNodeConnectionInfo(5, 6, TbMsgType.POST_ATTRIBUTES_REQUEST.getRuleNodeConnection()));
result.add(createNodeConnectionInfo(5, 3, TbNodeConnectionType.OTHER));
result.add(createNodeConnectionInfo(5, 2, TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.getRuleNodeConnection()));
result.add(createNodeConnectionInfo(6, 1, TbNodeConnectionType.SUCCESS));
result.add(createNodeConnectionInfo(7, 1, TbNodeConnectionType.SUCCESS));
result.add(createNodeConnectionInfo(8, 11, TbNodeConnectionType.SUCCESS));
result.add(createNodeConnectionInfo(8, 5, TbNodeConnectionType.SUCCESS));
result.add(createNodeConnectionInfo(8, 0, TbNodeConnectionType.SUCCESS));
return result;
}

3
application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java

@ -33,6 +33,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST;
@DaoSqlTest
@TestPropertySource(properties = {
@ -121,7 +122,7 @@ class NashornJsInvokeServiceTest extends AbstractControllerTest {
}
private String invokeScript(UUID scriptId, String msg) throws ExecutionException, InterruptedException {
return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", "POST_TELEMETRY_REQUEST").get().toString();
return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name()).get().toString();
}
}

3
application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java

@ -42,6 +42,7 @@ import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST;
@DaoSqlTest
@TestPropertySource(properties = {
@ -216,7 +217,7 @@ class TbelInvokeServiceTest extends AbstractControllerTest {
private String invokeScript(UUID scriptId, String str) throws ExecutionException, InterruptedException {
var msg = JacksonUtil.fromString(str, Map.class);
return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", "POST_TELEMETRY_REQUEST").get().toString();
return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name()).get().toString();
}
}

4
application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java

@ -33,11 +33,11 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.JsonDataEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.controller.AbstractControllerTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
@ -133,7 +133,7 @@ public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest
void saveLatestTsForAssetAndDevice(List<Device> devices, Asset asset, int idx) throws ExecutionException, InterruptedException, TimeoutException {
for (Device device : devices) {
TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(),
TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST,
device.getId(),
getTbMsgMetadata(device.getName(), ts.get(idx)),
TbMsgDataType.JSON,

5
application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java

@ -52,6 +52,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.relation.EntityRelation;
@ -343,7 +344,7 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest
metaData.setNodes(Arrays.asList(ruleNode1, ruleNode2));
metaData.setFirstNodeIndex(0);
metaData.addConnectionInfo(0, 1, "Success");
metaData.addConnectionInfo(0, 1, TbNodeConnectionType.SUCCESS);
ruleChainService.saveRuleChainMetaData(tenantId, metaData, Function.identity());
return ruleChainService.findRuleChainById(tenantId, ruleChain.getId());
@ -381,7 +382,7 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest
metaData.setNodes(Arrays.asList(ruleNode1, ruleNode2));
metaData.setFirstNodeIndex(0);
metaData.addConnectionInfo(0, 1, "Success");
metaData.addConnectionInfo(0, 1, TbNodeConnectionType.SUCCESS);
ruleChainService.saveRuleChainMetaData(tenantId, metaData, Function.identity());
return ruleChainService.findRuleChainById(tenantId, ruleChain.getId());

1
common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java

@ -109,6 +109,7 @@ public class DataConstants {
public static final String PROVISION_KEY = "provisionDeviceKey";
public static final String PROVISION_SECRET = "provisionDeviceSecret";
public static final String DEFAULT_DEVICE_TYPE = "default";
public static final String DEVICE_NAME = "deviceName";
public static final String DEVICE_TYPE = "deviceType";
public static final String CERT_PUB_KEY = "x509CertPubKey";

26
common/data/src/main/java/org/thingsboard/server/common/data/EntityFieldsData.java

@ -68,20 +68,22 @@ public class EntityFieldsData {
break;
}
}
if (current != null) {
if(current.isNull() && ignoreNullStrings){
if (current == null) {
return null;
}
if (current.isNull() && ignoreNullStrings) {
return null;
}
if (current.isValueNode()) {
String textValue = current.asText();
if (StringUtils.isEmpty(textValue) && ignoreNullStrings) {
return null;
}
if (current.isValueNode()) {
return current.asText();
} else {
try {
return mapper.writeValueAsString(current);
} catch (JsonProcessingException e) {
return null;
}
}
} else {
return textValue;
}
try {
return mapper.writeValueAsString(current);
} catch (JsonProcessingException e) {
return null;
}
}

15
common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java

@ -18,6 +18,10 @@ package org.thingsboard.server.common.data;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Andrew Shvayka
*/
@ -31,7 +35,13 @@ public enum EntityType {
ALARM,
RULE_CHAIN,
RULE_NODE,
ENTITY_VIEW,
ENTITY_VIEW {
// backward compatibility for TbOriginatorTypeSwitchNode to return correct rule node connection.
@Override
public String getNormalName() {
return "Entity View";
}
},
WIDGETS_BUNDLE,
WIDGET_TYPE,
TENANT_PROFILE,
@ -49,6 +59,9 @@ public enum EntityType {
NOTIFICATION,
NOTIFICATION_RULE;
public static final List<String> NORMAL_NAMES = EnumSet.allOf(EntityType.class).stream()
.map(EntityType::getNormalName).collect(Collectors.toUnmodifiableList());
@Getter
private final String normalName = StringUtils.capitalize(StringUtils.removeStart(name(), "TB_")
.toLowerCase().replaceAll("_", " "));

88
common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java

@ -16,49 +16,61 @@
package org.thingsboard.server.common.data.audit;
import lombok.Getter;
import org.thingsboard.server.common.data.msg.TbMsgType;
import java.util.Optional;
@Getter
public enum ActionType {
ADDED(false), // log entity
DELETED(false), // log string id
UPDATED(false), // log entity
ATTRIBUTES_UPDATED(false), // log attributes/values
ATTRIBUTES_DELETED(false), // log attributes
TIMESERIES_UPDATED(false), // log timeseries update
TIMESERIES_DELETED(false), // log timeseries
RPC_CALL(false), // log method and params
CREDENTIALS_UPDATED(false), // log new credentials
ASSIGNED_TO_CUSTOMER(false), // log customer name
UNASSIGNED_FROM_CUSTOMER(false), // log customer name
ACTIVATED(false), // log string id
SUSPENDED(false), // log string id
CREDENTIALS_READ(true), // log device id
ATTRIBUTES_READ(true), // log attributes
RELATION_ADD_OR_UPDATE(false),
RELATION_DELETED(false),
RELATIONS_DELETED(false),
ALARM_ACK(false),
ALARM_CLEAR(false),
ALARM_DELETE(false),
ALARM_ASSIGNED(false),
ALARM_UNASSIGNED(false),
LOGIN(false),
LOGOUT(false),
LOCKOUT(false),
ASSIGNED_FROM_TENANT(false),
ASSIGNED_TO_TENANT(false),
PROVISION_SUCCESS(false),
PROVISION_FAILURE(false),
ASSIGNED_TO_EDGE(false), // log edge name
UNASSIGNED_FROM_EDGE(false),
ADDED_COMMENT(false),
UPDATED_COMMENT(false),
DELETED_COMMENT(false),
SMS_SENT(false);
ADDED(false, TbMsgType.ENTITY_CREATED), // log entity
DELETED(false, TbMsgType.ENTITY_DELETED), // log string id
UPDATED(false, TbMsgType.ENTITY_UPDATED), // log entity
ATTRIBUTES_UPDATED(false, TbMsgType.ATTRIBUTES_UPDATED), // log attributes/values
ATTRIBUTES_DELETED(false, TbMsgType.ATTRIBUTES_DELETED), // log attributes
TIMESERIES_UPDATED(false, TbMsgType.TIMESERIES_UPDATED), // log timeseries update
TIMESERIES_DELETED(false, TbMsgType.TIMESERIES_DELETED), // log timeseries
RPC_CALL(false, null), // log method and params
CREDENTIALS_UPDATED(false, null), // log new credentials
ASSIGNED_TO_CUSTOMER(false, TbMsgType.ENTITY_ASSIGNED), // log customer name
UNASSIGNED_FROM_CUSTOMER(false, TbMsgType.ENTITY_UNASSIGNED), // log customer name
ACTIVATED(false, null), // log string id
SUSPENDED(false, null), // log string id
CREDENTIALS_READ(true, null), // log device id
ATTRIBUTES_READ(true, null), // log attributes
RELATION_ADD_OR_UPDATE(false, TbMsgType.RELATION_ADD_OR_UPDATE),
RELATION_DELETED(false, TbMsgType.RELATION_DELETED),
RELATIONS_DELETED(false, TbMsgType.RELATIONS_DELETED),
ALARM_ACK(false, TbMsgType.ALARM_ACK),
ALARM_CLEAR(false, TbMsgType.ALARM_CLEAR),
ALARM_DELETE(false, TbMsgType.ALARM_DELETE),
ALARM_ASSIGNED(false, TbMsgType.ALARM_ASSIGNED),
ALARM_UNASSIGNED(false, TbMsgType.ALARM_UNASSIGNED),
LOGIN(false, null),
LOGOUT(false, null),
LOCKOUT(false, null),
ASSIGNED_FROM_TENANT(false, TbMsgType.ENTITY_ASSIGNED_FROM_TENANT),
ASSIGNED_TO_TENANT(false, TbMsgType.ENTITY_ASSIGNED_TO_TENANT),
PROVISION_SUCCESS(false, TbMsgType.PROVISION_SUCCESS),
PROVISION_FAILURE(false, TbMsgType.PROVISION_FAILURE),
ASSIGNED_TO_EDGE(false, TbMsgType.ENTITY_ASSIGNED_TO_EDGE), // log edge name
UNASSIGNED_FROM_EDGE(false, TbMsgType.ENTITY_UNASSIGNED_FROM_EDGE),
ADDED_COMMENT(false, TbMsgType.COMMENT_CREATED),
UPDATED_COMMENT(false, TbMsgType.COMMENT_UPDATED),
DELETED_COMMENT(false, null),
SMS_SENT(false, null);
@Getter
private final boolean isRead;
ActionType(boolean isRead) {
private final TbMsgType ruleEngineMsgType;
ActionType(boolean isRead, TbMsgType ruleEngineMsgType) {
this.isRead = isRead;
this.ruleEngineMsgType = ruleEngineMsgType;
}
public Optional<TbMsgType> getRuleEngineMsgType() {
return Optional.ofNullable(ruleEngineMsgType);
}
}

115
common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java

@ -0,0 +1,115 @@
/**
* Copyright © 2016-2023 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.common.data.msg;
import lombok.Getter;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public enum TbMsgType {
POST_ATTRIBUTES_REQUEST("Post attributes"),
POST_TELEMETRY_REQUEST("Post telemetry"),
TO_SERVER_RPC_REQUEST("RPC Request from Device"),
ACTIVITY_EVENT("Activity Event"),
INACTIVITY_EVENT("Inactivity Event"),
CONNECT_EVENT("Connect Event"),
DISCONNECT_EVENT("Disconnect Event"),
ENTITY_CREATED("Entity Created"),
ENTITY_UPDATED("Entity Updated"),
ENTITY_DELETED("Entity Deleted"),
ENTITY_ASSIGNED("Entity Assigned"),
ENTITY_UNASSIGNED("Entity Unassigned"),
ATTRIBUTES_UPDATED("Attributes Updated"),
ATTRIBUTES_DELETED("Attributes Deleted"),
ALARM(null),
ALARM_ACK("Alarm Acknowledged"),
ALARM_CLEAR("Alarm Cleared"),
ALARM_DELETE(null),
ALARM_ASSIGNED("Alarm Assigned"),
ALARM_UNASSIGNED("Alarm Unassigned"),
COMMENT_CREATED("Comment Created"),
COMMENT_UPDATED("Comment Updated"),
RPC_CALL_FROM_SERVER_TO_DEVICE("RPC Request to Device"),
ENTITY_ASSIGNED_FROM_TENANT("Entity Assigned From Tenant"),
ENTITY_ASSIGNED_TO_TENANT("Entity Assigned To Tenant"),
ENTITY_ASSIGNED_TO_EDGE(null),
ENTITY_UNASSIGNED_FROM_EDGE(null),
TIMESERIES_UPDATED("Timeseries Updated"),
TIMESERIES_DELETED("Timeseries Deleted"),
RPC_QUEUED("RPC Queued"),
RPC_SENT("RPC Sent"),
RPC_DELIVERED("RPC Delivered"),
RPC_SUCCESSFUL("RPC Successful"),
RPC_TIMEOUT("RPC Timeout"),
RPC_EXPIRED("RPC Expired"),
RPC_FAILED("RPC Failed"),
RPC_DELETED("RPC Deleted"),
RELATION_ADD_OR_UPDATE("Relation Added or Updated"),
RELATION_DELETED("Relation Deleted"),
RELATIONS_DELETED("All Relations Deleted"),
PROVISION_SUCCESS(null),
PROVISION_FAILURE(null),
SEND_EMAIL(null),
// tellSelfOnly types
GENERATOR_NODE_SELF_MSG(null, true),
DEVICE_PROFILE_PERIODIC_SELF_MSG(null, true),
DEVICE_PROFILE_UPDATE_SELF_MSG(null, true),
DEVICE_UPDATE_SELF_MSG(null, true),
DEDUPLICATION_TIMEOUT_SELF_MSG(null, true),
DELAY_TIMEOUT_SELF_MSG(null, true),
MSG_COUNT_SELF_MSG(null, true);
public static final List<String> NODE_CONNECTIONS = EnumSet.allOf(TbMsgType.class).stream()
.filter(tbMsgType -> !tbMsgType.isTellSelfOnly())
.map(TbMsgType::getRuleNodeConnection)
.filter(Objects::nonNull)
.collect(Collectors.toUnmodifiableList());
@Getter
private final String ruleNodeConnection;
@Getter
private final boolean tellSelfOnly;
TbMsgType(String ruleNodeConnection, boolean tellSelfOnly) {
this.ruleNodeConnection = ruleNodeConnection;
this.tellSelfOnly = tellSelfOnly;
}
TbMsgType(String ruleNodeConnection) {
this.ruleNodeConnection = ruleNodeConnection;
this.tellSelfOnly = false;
}
public static String getRuleNodeConnectionOrElseOther(String msgType) {
if (msgType == null) {
return TbNodeConnectionType.OTHER;
} else {
return Arrays.stream(TbMsgType.values())
.filter(type -> type.name().equals(msgType))
.findFirst()
.map(TbMsgType::getRuleNodeConnection)
.orElse(TbNodeConnectionType.OTHER);
}
}
}

13
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbRelationTypes.java → common/data/src/main/java/org/thingsboard/server/common/data/msg/TbNodeConnectionType.java

@ -13,14 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.rule.engine.api;
package org.thingsboard.server.common.data.msg;
/**
* Created by ashvayka on 19.01.18.
*/
public final class TbRelationTypes {
public final class TbNodeConnectionType {
public static String SUCCESS = "Success";
public static String FAILURE = "Failure";
public static final String SUCCESS = "Success";
public static final String FAILURE = "Failure";
public static final String TRUE = "True";
public static final String FALSE = "False";
public static final String OTHER = "Other";
}

30
common/data/src/test/java/org/thingsboard/server/common/data/EntityTypeTest.java

@ -0,0 +1,30 @@
/**
* Copyright © 2016-2023 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.common.data;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class EntityTypeTest {
// backward-compatibility test
@Test
void getNormalNameTest() {
assertThat(EntityType.ENTITY_VIEW.getNormalName()).isEqualTo("Entity View");
}
}

65
common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java

@ -0,0 +1,65 @@
/**
* Copyright © 2016-2023 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.common.data.audit;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.thingsboard.server.common.data.audit.ActionType.ACTIVATED;
import static org.thingsboard.server.common.data.audit.ActionType.ATTRIBUTES_READ;
import static org.thingsboard.server.common.data.audit.ActionType.CREDENTIALS_READ;
import static org.thingsboard.server.common.data.audit.ActionType.CREDENTIALS_UPDATED;
import static org.thingsboard.server.common.data.audit.ActionType.DELETED_COMMENT;
import static org.thingsboard.server.common.data.audit.ActionType.LOCKOUT;
import static org.thingsboard.server.common.data.audit.ActionType.LOGIN;
import static org.thingsboard.server.common.data.audit.ActionType.LOGOUT;
import static org.thingsboard.server.common.data.audit.ActionType.RPC_CALL;
import static org.thingsboard.server.common.data.audit.ActionType.SMS_SENT;
import static org.thingsboard.server.common.data.audit.ActionType.SUSPENDED;
class ActionTypeTest {
private static final List<ActionType> typesWithNullRuleEngineMsgType = List.of(
RPC_CALL,
CREDENTIALS_UPDATED,
ACTIVATED,
SUSPENDED,
CREDENTIALS_READ,
ATTRIBUTES_READ,
LOGIN,
LOGOUT,
LOCKOUT,
DELETED_COMMENT,
SMS_SENT
);
// backward-compatibility tests
@Test
void getRuleEngineMsgTypeTest() {
var types = ActionType.values();
for (var type : types) {
if (typesWithNullRuleEngineMsgType.contains(type)) {
assertThat(type.getRuleEngineMsgType()).isEmpty();
} else {
assertThat(type.getRuleEngineMsgType()).isPresent();
}
}
}
}

87
common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java

@ -0,0 +1,87 @@
/**
* Copyright © 2016-2023 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.common.data.msg;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM;
import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_DELETE;
import static org.thingsboard.server.common.data.msg.TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG;
import static org.thingsboard.server.common.data.msg.TbMsgType.DELAY_TIMEOUT_SELF_MSG;
import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_ASSIGNED_TO_EDGE;
import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_UNASSIGNED_FROM_EDGE;
import static org.thingsboard.server.common.data.msg.TbMsgType.MSG_COUNT_SELF_MSG;
import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_FAILURE;
import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_SUCCESS;
import static org.thingsboard.server.common.data.msg.TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG;
import static org.thingsboard.server.common.data.msg.TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG;
import static org.thingsboard.server.common.data.msg.TbMsgType.DEVICE_UPDATE_SELF_MSG;
import static org.thingsboard.server.common.data.msg.TbMsgType.GENERATOR_NODE_SELF_MSG;
import static org.thingsboard.server.common.data.msg.TbMsgType.SEND_EMAIL;
class TbMsgTypeTest {
private static final List<TbMsgType> typesWithNullRuleNodeConnection = List.of(
ALARM,
ALARM_DELETE,
ENTITY_ASSIGNED_TO_EDGE,
ENTITY_UNASSIGNED_FROM_EDGE,
PROVISION_FAILURE,
PROVISION_SUCCESS,
SEND_EMAIL,
GENERATOR_NODE_SELF_MSG,
DEVICE_PROFILE_PERIODIC_SELF_MSG,
DEVICE_PROFILE_UPDATE_SELF_MSG,
DEVICE_UPDATE_SELF_MSG,
DEDUPLICATION_TIMEOUT_SELF_MSG,
DELAY_TIMEOUT_SELF_MSG,
MSG_COUNT_SELF_MSG
);
// backward-compatibility tests
@Test
void getRuleNodeConnectionsTest() {
var tbMsgTypes = TbMsgType.values();
for (var type : tbMsgTypes) {
if (typesWithNullRuleNodeConnection.contains(type)) {
assertThat(type.getRuleNodeConnection()).isNull();
} else {
assertThat(type.getRuleNodeConnection()).isNotNull();
}
}
}
@Test
void getRuleNodeConnectionOrElseOtherTest() {
assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(null))
.isEqualTo(TbNodeConnectionType.OTHER);
var tbMsgTypes = TbMsgType.values();
for (var type : tbMsgTypes) {
if (typesWithNullRuleNodeConnection.contains(type)) {
assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type.name()))
.isEqualTo(TbNodeConnectionType.OTHER);
} else {
assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type.name())).isNotNull()
.isNotEqualTo(TbNodeConnectionType.OTHER);
}
}
}
}

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

@ -29,10 +29,12 @@ import org.thingsboard.server.common.data.id.EntityId;
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.data.msg.TbMsgType;
import org.thingsboard.server.common.msg.gen.MsgProtos;
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
import java.io.Serializable;
import java.util.Objects;
import java.util.UUID;
/**
@ -42,6 +44,10 @@ import java.util.UUID;
@Slf4j
public final class TbMsg implements Serializable {
public static final String EMPTY_JSON_OBJECT = "{}";
public static final String EMPTY_JSON_ARRAY = "[]";
public static final String EMPTY_STRING = "";
private final String queueName;
private final UUID id;
private final long ts;
@ -66,82 +72,234 @@ public final class TbMsg implements Serializable {
return ctx.getAndIncrementRuleNodeCounter();
}
@Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return newMsg(queueName, type, originator, null, metaData, data, ruleChainId, ruleNodeId);
}
/**
* Creates a new TbMsg instance with the specified parameters.
*
* <p><strong>Deprecated:</strong> This method is deprecated since version 3.5.2 and should only be used when you need to
* specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types,
* it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, CustomerId, TbMsgMetaData, String, RuleChainId, RuleNodeId)}
* method instead.</p>
*
* @param queueName the name of the queue where the message will be sent
* @param type the type of the message
* @param originator the originator of the message
* @param customerId the ID of the customer associated with the message
* @param metaData the metadata of the message
* @param data the data of the message
* @param ruleChainId the ID of the rule chain associated with the message
* @param ruleNodeId the ID of the rule node associated with the message
* @return new TbMsg instance
*/
@Deprecated(since = "3.5.2")
public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId,
metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY);
}
@Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) {
return newMsg(type, originator, null, metaData, data);
}
@Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId,
metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY);
}
public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return newMsg(queueName, type, originator, null, metaData, data, ruleChainId, ruleNodeId);
}
public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId,
metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY);
}
public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) {
return newMsg(type, originator, null, metaData, data);
}
public static TbMsg newMsg(TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId,
metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY);
}
// REALLY NEW MSG
/**
* Creates a new TbMsg instance with the specified parameters.
*
* <p><strong>Deprecated:</strong> This method is deprecated since version 3.5.2 and should only be used when you need to
* specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types,
* it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, TbMsgMetaData, String)}
* method instead.</p>
*
* @param queueName the name of the queue where the message will be sent
* @param type the type of the message
* @param originator the originator of the message
* @param metaData the metadata of the message
* @param data the data of the message
* @return new TbMsg instance
*/
@Deprecated(since = "3.5.2")
public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) {
return newMsg(queueName, type, originator, null, metaData, data);
}
/**
* Creates a new TbMsg instance with the specified parameters.
*
* <p><strong>Deprecated:</strong> This method is deprecated since version 3.5.2 and should only be used when you need to
* specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types,
* it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, CustomerId, TbMsgMetaData, String)}
* method instead.</p>
*
* @param queueName the name of the queue where the message will be sent
* @param type the type of the message
* @param originator the originator of the message
* @param customerId the ID of the customer associated with the message
* @param metaData the metadata of the message
* @param data the data of the message
* @return new TbMsg instance
*/
@Deprecated(since = "3.5.2")
public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId,
metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY);
}
@Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId,
metaData.copy(), dataType, data, null, null, null, TbMsgCallback.EMPTY);
}
/**
* Creates a new TbMsg instance with the specified parameters.
*
* <p><strong>Deprecated:</strong> This method is deprecated since version 3.5.2 and should only be used when you need to
* specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types,
* it is recommended to use the {@link #newMsg(TbMsgType, EntityId, TbMsgMetaData, TbMsgDataType, String)}
* method instead.</p>
*
* @param type the type of the message
* @param originator the originator of the message
* @param metaData the metadata of the message
* @param dataType the dataType of the message
* @param data the data of the message
* @return new TbMsg instance
*/
@Deprecated(since = "3.5.2")
public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) {
return newMsg(type, originator, null, metaData, dataType, data);
}
public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) {
return newMsg(queueName, type, originator, null, metaData, data);
}
public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId,
metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY);
}
public static TbMsg newMsg(TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId,
metaData.copy(), dataType, data, null, null, null, TbMsgCallback.EMPTY);
}
public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) {
return newMsg(type, originator, null, metaData, dataType, data);
}
// For Tests only
@Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null,
metaData.copy(), dataType, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY);
}
@Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null,
metaData.copy(), TbMsgDataType.JSON, data, null, null, null, callback);
}
/**
* Transforms an existing TbMsg instance by changing its message type, originator, metadata, and data.
*
* <p><strong>Deprecated:</strong> This method is deprecated since version 3.5.2 and should only be used when you need to
* specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types,
* it is recommended to use the {@link #transformMsg(TbMsg, TbMsgType, EntityId, TbMsgMetaData, String)}
* method instead.</p>
*
*
* @param tbMsg the TbMsg instance to transform
* @param type the new message type
* @param originator the new originator
* @param metaData the new metadata
* @param data the new data
* @return the transformed TbMsg instance
*/
@Deprecated(since = "3.5.2")
public static TbMsg transformMsg(TbMsg tbMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType,
data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback);
}
public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, null,
metaData.copy(), dataType, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY);
}
public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, null,
metaData.copy(), TbMsgDataType.JSON, data, null, null, null, callback);
}
public static TbMsg transformMsg(TbMsg tbMsg, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type.name(), originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType,
data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback);
}
public static TbMsg transformMsgOriginator(TbMsg tbMsg, EntityId originatorId) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, originatorId, tbMsg.getCustomerId(), tbMsg.metaData, tbMsg.dataType,
tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback());
}
public static TbMsg transformMsgData(TbMsg tbMsg, String data) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback());
}
public static TbMsg transformMsg(TbMsg tbMsg, TbMsgMetaData metadata) {
public static TbMsg transformMsgMetadata(TbMsg tbMsg, TbMsgMetaData metadata) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata.copy(), tbMsg.dataType,
tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback());
}
public static TbMsg transformMsg(TbMsg tbMsg, CustomerId customerId) {
public static TbMsg transformMsg(TbMsg tbMsg, TbMsgMetaData metadata, String data) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata, tbMsg.dataType,
data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback());
}
public static TbMsg transformMsgCustomerId(TbMsg tbMsg, CustomerId customerId) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType,
tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback());
}
public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId) {
public static TbMsg transformMsgRuleChainId(TbMsg tbMsg, RuleChainId ruleChainId) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
tbMsg.data, ruleChainId, null, tbMsg.ctx.copy(), tbMsg.getCallback());
}
public static TbMsg transformMsg(TbMsg tbMsg, String queueName) {
public static TbMsg transformMsgQueueName(TbMsg tbMsg, String queueName) {
return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
tbMsg.data, tbMsg.getRuleChainId(), null, tbMsg.ctx.copy(), tbMsg.getCallback());
}
@ -183,11 +341,7 @@ public final class TbMsg implements Serializable {
this.ruleChainId = ruleChainId;
this.ruleNodeId = ruleNodeId;
this.ctx = ctx != null ? ctx : new TbMsgProcessingCtx();
if (callback != null) {
this.callback = callback;
} else {
this.callback = TbMsgCallback.EMPTY;
}
this.callback = Objects.requireNonNullElse(callback, TbMsgCallback.EMPTY);
}
public static ByteString toByteString(TbMsg msg) {
@ -284,11 +438,7 @@ public final class TbMsg implements Serializable {
public TbMsgCallback getCallback() {
// May be null in case of deserialization;
if (callback != null) {
return callback;
} else {
return TbMsgCallback.EMPTY;
}
return Objects.requireNonNullElse(callback, TbMsgCallback.EMPTY);
}
public void pushToStack(RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
@ -317,4 +467,18 @@ public final class TbMsg implements Serializable {
}
return ts;
}
public boolean isTypeOf(TbMsgType tbMsgType) {
return tbMsgType != null && tbMsgType.name().equals(this.type);
}
public boolean isTypeOneOf(TbMsgType... types) {
for (TbMsgType type : types) {
if (isTypeOf(type)) {
return true;
}
}
return false;
}
}

6
common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java

@ -15,6 +15,12 @@
*/
package org.thingsboard.server.common.msg.session;
/**
* @deprecated This enum is deprecated and will be removed in a future version.
* Note: This enum was originally part of the public API but is now specific to CoAP transport only.
* Please use {@link org.thingsboard.server.transport.coap.CoapSessionMsgType} instead.
*/
@Deprecated(since="3.5.2", forRemoval = true)
public enum SessionMsgType {
GET_ATTRIBUTES_REQUEST(true), POST_ATTRIBUTES_REQUEST(true), GET_ATTRIBUTES_RESPONSE,
SUBSCRIBE_ATTRIBUTES_REQUEST, UNSUBSCRIBE_ATTRIBUTES_REQUEST, ATTRIBUTES_UPDATE_NOTIFICATION,

31
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapSessionMsgType.java

@ -0,0 +1,31 @@
/**
* Copyright © 2016-2023 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.transport.coap;
public enum CoapSessionMsgType {
GET_ATTRIBUTES_REQUEST,
POST_ATTRIBUTES_REQUEST,
SUBSCRIBE_ATTRIBUTES_REQUEST,
UNSUBSCRIBE_ATTRIBUTES_REQUEST,
POST_TELEMETRY_REQUEST,
SUBSCRIBE_RPC_COMMANDS_REQUEST,
UNSUBSCRIBE_RPC_COMMANDS_REQUEST,
TO_DEVICE_RPC_RESPONSE,
TO_SERVER_RPC_REQUEST,
CLAIM_REQUEST;
}

27
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java

@ -33,7 +33,6 @@ import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
@ -120,7 +119,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
} else if (exchange.getRequestOptions().hasObserve()) {
processExchangeGetRequest(exchange, featureType.get());
} else if (featureType.get() == FeatureType.ATTRIBUTES) {
processRequest(exchange, SessionMsgType.GET_ATTRIBUTES_REQUEST);
processRequest(exchange, CoapSessionMsgType.GET_ATTRIBUTES_REQUEST);
} else {
log.trace("Invalid feature type parameter");
exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
@ -129,13 +128,13 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
private void processExchangeGetRequest(CoapExchange exchange, FeatureType featureType) {
boolean unsubscribe = exchange.getRequestOptions().getObserve() == 1;
SessionMsgType sessionMsgType;
CoapSessionMsgType coapSessionMsgType;
if (featureType == FeatureType.RPC) {
sessionMsgType = unsubscribe ? SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST : SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST;
coapSessionMsgType = unsubscribe ? CoapSessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST : CoapSessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST;
} else {
sessionMsgType = unsubscribe ? SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST : SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST;
coapSessionMsgType = unsubscribe ? CoapSessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST : CoapSessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST;
}
processRequest(exchange, sessionMsgType);
processRequest(exchange, coapSessionMsgType);
}
@Override
@ -147,21 +146,21 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
} else {
switch (featureType.get()) {
case ATTRIBUTES:
processRequest(exchange, SessionMsgType.POST_ATTRIBUTES_REQUEST);
processRequest(exchange, CoapSessionMsgType.POST_ATTRIBUTES_REQUEST);
break;
case TELEMETRY:
processRequest(exchange, SessionMsgType.POST_TELEMETRY_REQUEST);
processRequest(exchange, CoapSessionMsgType.POST_TELEMETRY_REQUEST);
break;
case RPC:
Optional<Integer> requestId = getRequestId(exchange.advanced().getRequest());
if (requestId.isPresent()) {
processRequest(exchange, SessionMsgType.TO_DEVICE_RPC_RESPONSE);
processRequest(exchange, CoapSessionMsgType.TO_DEVICE_RPC_RESPONSE);
} else {
processRequest(exchange, SessionMsgType.TO_SERVER_RPC_REQUEST);
processRequest(exchange, CoapSessionMsgType.TO_SERVER_RPC_REQUEST);
}
break;
case CLAIM:
processRequest(exchange, SessionMsgType.CLAIM_REQUEST);
processRequest(exchange, CoapSessionMsgType.CLAIM_REQUEST);
break;
case PROVISION:
processProvision(exchange);
@ -195,7 +194,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
}
}
private void processRequest(CoapExchange exchange, SessionMsgType type) {
private void processRequest(CoapExchange exchange, CoapSessionMsgType type) {
log.trace("Processing {}", exchange.advanced().getRequest());
deferAccept(exchange);
Exchange advanced = exchange.advanced();
@ -218,7 +217,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
}
}
private void processAccessTokenRequest(CoapExchange exchange, SessionMsgType type, Request request) {
private void processAccessTokenRequest(CoapExchange exchange, CoapSessionMsgType type, Request request) {
Optional<DeviceTokenCredentials> credentials = decodeCredentials(request);
if (credentials.isEmpty()) {
exchange.respond(CoAP.ResponseCode.UNAUTHORIZED);
@ -228,7 +227,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
new CoapDeviceAuthCallback(exchange, (deviceCredentials, deviceProfile) -> processRequest(exchange, type, request, deviceCredentials, deviceProfile)));
}
private void processRequest(CoapExchange exchange, SessionMsgType type, Request request, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) {
private void processRequest(CoapExchange exchange, CoapSessionMsgType type, Request request, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) {
TbCoapClientState clientState = null;
try {
clientState = clients.getOrCreateClient(type, deviceCredentials, deviceProfile);

4
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/CoapClientContext.java

@ -18,7 +18,7 @@ package org.thingsboard.server.transport.coap.client;
import org.eclipse.californium.core.observe.ObserveRelation;
import org.eclipse.californium.core.server.resources.CoapExchange;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.transport.coap.CoapSessionMsgType;
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos;
@ -33,7 +33,7 @@ public interface CoapClientContext {
AtomicInteger getNotificationCounterByToken(String token);
TbCoapClientState getOrCreateClient(SessionMsgType type, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) throws AdaptorException;
TbCoapClientState getOrCreateClient(CoapSessionMsgType type, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) throws AdaptorException;
TransportProtos.SessionInfoProto getNewSyncSession(TbCoapClientState clientState);

4
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DefaultCoapClientContext.java

@ -45,7 +45,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.transport.coap.CoapSessionMsgType;
import org.thingsboard.server.common.transport.DeviceDeletedEvent;
import org.thingsboard.server.common.transport.DeviceProfileUpdatedEvent;
import org.thingsboard.server.common.transport.DeviceUpdatedEvent;
@ -388,7 +388,7 @@ public class DefaultCoapClientContext implements CoapClientContext {
}
@Override
public TbCoapClientState getOrCreateClient(SessionMsgType type, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) throws AdaptorException {
public TbCoapClientState getOrCreateClient(CoapSessionMsgType type, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) throws AdaptorException {
DeviceId deviceId = deviceCredentials.getDeviceInfo().getDeviceId();
TbCoapClientState state = getClientState(deviceId);
state.lock();

2
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java

@ -71,6 +71,7 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;
import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE;
import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED;
import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN;
import static org.thingsboard.server.common.transport.service.DefaultTransportService.SUBSCRIBE_TO_ATTRIBUTE_UPDATES_ASYNC_MSG;
@ -85,7 +86,6 @@ import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMess
@Slf4j
public abstract class AbstractGatewaySessionHandler<T extends AbstractGatewayDeviceSessionContext> {
protected static final String DEFAULT_DEVICE_TYPE = "default";
private static final String CAN_T_PARSE_VALUE = "Can't parse value: ";
private static final String DEVICE_PROPERTY = "device";

14
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java

@ -49,14 +49,14 @@ import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.limit.LimitedApi;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsTrigger;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsTrigger;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
import org.thingsboard.server.common.stats.MessagesStats;
import org.thingsboard.server.common.stats.StatsFactory;
@ -583,7 +583,7 @@ public class DefaultTransportService implements TransportService {
metaData.putValue("deviceType", sessionInfo.getDeviceType());
metaData.putValue("ts", tsKv.getTs() + "");
JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
sendToRuleEngine(tenantId, deviceId, customerId, sessionInfo, json, metaData, SessionMsgType.POST_TELEMETRY_REQUEST, packCallback);
sendToRuleEngine(tenantId, deviceId, customerId, sessionInfo, json, metaData, TbMsgType.POST_TELEMETRY_REQUEST, packCallback);
}
}
}
@ -603,7 +603,7 @@ public class DefaultTransportService implements TransportService {
}
metaData.putValue(DataConstants.NOTIFY_DEVICE_METADATA_KEY, "false");
CustomerId customerId = getCustomerId(sessionInfo);
sendToRuleEngine(tenantId, deviceId, customerId, sessionInfo, json, metaData, SessionMsgType.POST_ATTRIBUTES_REQUEST,
sendToRuleEngine(tenantId, deviceId, customerId, sessionInfo, json, metaData, TbMsgType.POST_ATTRIBUTES_REQUEST,
new TransportTbQueueCallback(new ApiStatsProxyCallback<>(tenantId, customerId, msg.getKvList().size(), callback)));
}
}
@ -723,7 +723,7 @@ public class DefaultTransportService implements TransportService {
metaData.putValue("serviceId", serviceInfoProvider.getServiceId());
metaData.putValue("sessionId", sessionId.toString());
sendToRuleEngine(tenantId, deviceId, getCustomerId(sessionInfo), sessionInfo, json, metaData,
SessionMsgType.TO_SERVER_RPC_REQUEST, new TransportTbQueueCallback(callback));
TbMsgType.TO_SERVER_RPC_REQUEST, new TransportTbQueueCallback(callback));
String requestId = sessionId + "-" + msg.getRequestId();
toServerRpcPendingMap.put(requestId, new RpcRequestMetadata(sessionId, msg.getRequestId()));
scheduler.schedule(() -> processTimeout(requestId), clientSideRpcTimeout, TimeUnit.MILLISECONDS);
@ -1136,7 +1136,7 @@ public class DefaultTransportService implements TransportService {
}
private void sendToRuleEngine(TenantId tenantId, DeviceId deviceId, CustomerId customerId, TransportProtos.SessionInfoProto sessionInfo, JsonObject json,
TbMsgMetaData metaData, SessionMsgType sessionMsgType, TbQueueCallback callback) {
TbMsgMetaData metaData, TbMsgType tbMsgType, TbQueueCallback callback) {
DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId);
RuleChainId ruleChainId;
@ -1151,7 +1151,7 @@ public class DefaultTransportService implements TransportService {
queueName = deviceProfile.getDefaultQueueName();
}
TbMsg tbMsg = TbMsg.newMsg(queueName, sessionMsgType.name(), deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null);
TbMsg tbMsg = TbMsg.newMsg(queueName, tbMsgType, deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null);
sendToRuleEngine(tenantId, tbMsg, callback);
}

5
dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java

@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.event.RuleChainDebugEventFilter;
import org.thingsboard.server.common.data.event.RuleNodeDebugEventFilter;
import org.thingsboard.server.common.data.event.StatisticsEventFilter;
import org.thingsboard.server.common.data.id.EventId;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.stats.StatsFactory;
@ -280,7 +281,7 @@ public class JpaBaseEventDao implements EventDao {
private PageData<? extends Event> findEventByFilter(UUID tenantId, UUID entityId, LifeCycleEventFilter eventFilter, TimePageLink pageLink) {
boolean statusFilterEnabled = !StringUtils.isEmpty(eventFilter.getStatus());
boolean statusFilter = statusFilterEnabled && eventFilter.getStatus().equalsIgnoreCase("Success");
boolean statusFilter = statusFilterEnabled && eventFilter.getStatus().equalsIgnoreCase(TbNodeConnectionType.SUCCESS);
return DaoUtil.toPageData(
lcEventRepository.findEvents(
tenantId,
@ -359,7 +360,7 @@ public class JpaBaseEventDao implements EventDao {
private void removeEventsByFilter(UUID tenantId, UUID entityId, LifeCycleEventFilter eventFilter, Long startTime, Long endTime) {
boolean statusFilterEnabled = !StringUtils.isEmpty(eventFilter.getStatus());
boolean statusFilter = statusFilterEnabled && eventFilter.getStatus().equalsIgnoreCase("Success");
boolean statusFilter = statusFilterEnabled && eventFilter.getStatus().equalsIgnoreCase(TbNodeConnectionType.SUCCESS);
lcEventRepository.removeEvents(
tenantId,
entityId,

3
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EmptyNodeConfiguration.java

@ -24,7 +24,6 @@ public class EmptyNodeConfiguration implements NodeConfiguration<EmptyNodeConfig
@Override
public EmptyNodeConfiguration defaultConfiguration() {
EmptyNodeConfiguration configuration = new EmptyNodeConfiguration();
return configuration;
return new EmptyNodeConfiguration();
}
}

3
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.rule.engine.api;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentClusteringMode;
import org.thingsboard.server.common.data.plugin.ComponentScope;
import org.thingsboard.server.common.data.plugin.ComponentType;
@ -47,7 +48,7 @@ public @interface RuleNode {
ComponentScope scope() default ComponentScope.TENANT;
String[] relationTypes() default {"Success", "Failure"};
String[] relationTypes() default {TbNodeConnectionType.SUCCESS, TbNodeConnectionType.FAILURE};
String[] uiResources() default {};

34
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java

@ -36,6 +36,7 @@ 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.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.rule.RuleNode;
@ -183,21 +184,52 @@ public interface TbContext {
void ack(TbMsg tbMsg);
@Deprecated(since = "3.5.2", forRemoval = true)
TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data);
/**
* Creates a new TbMsg instance with the specified parameters.
*
* <p><strong>Deprecated:</strong> This method is deprecated since version 3.5.2 and should only be used when you need to
* specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types,
* it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, CustomerId, TbMsgMetaData, String)}
* method instead.</p>
*
* @param queueName the name of the queue where the message will be sent
* @param type the type of the message
* @param originator the originator of the message
* @param customerId the ID of the customer associated with the message
* @param metaData the metadata of the message
* @param data the data of the message
* @return new TbMsg instance
*/
@Deprecated(since = "3.5.2")
TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data);
@Deprecated(since = "3.5.2", forRemoval = true)
TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data);
TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data);
TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data);
TbMsg transformMsg(TbMsg origMsg, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data);
TbMsg transformMsg(TbMsg origMsg, TbMsgMetaData metaData, String data);
TbMsg transformMsgOriginator(TbMsg origMsg, EntityId originator);
TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId);
TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId);
TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId);
// TODO: Does this changes the message?
@Deprecated(since = "3.5.2", forRemoval = true)
TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action);
TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, TbMsgType actionMsgType);
TbMsg attributesUpdatedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List<AttributeKvEntry> attributes);
TbMsg attributesDeletedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List<String> keys);

11
rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java

@ -22,6 +22,7 @@ import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -43,7 +44,7 @@ public class TbNodeUtilsTest {
ObjectNode node = JacksonUtil.newObjectNode();
node.put("data_key", "data_value");
TbMsg msg = TbMsg.newMsg("CUSTOM", TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node));
TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node));
String result = TbNodeUtils.processPattern(pattern, msg);
Assert.assertEquals("ABC metadata_value data_value", result);
}
@ -57,7 +58,7 @@ public class TbNodeUtilsTest {
ObjectNode node = JacksonUtil.newObjectNode();
node.put("key", "data_value");
TbMsg msg = TbMsg.newMsg("CUSTOM", TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node));
TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node));
String result = TbNodeUtils.processPattern(pattern, msg);
Assert.assertEquals(pattern, result);
}
@ -71,7 +72,7 @@ public class TbNodeUtilsTest {
ObjectNode node = JacksonUtil.newObjectNode();
node.put("key", "data_value");
TbMsg msg = TbMsg.newMsg("CUSTOM", TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node));
TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node));
String result = TbNodeUtils.processPattern(pattern, msg);
Assert.assertEquals("ABC metadata_value data_value", result);
}
@ -92,7 +93,7 @@ public class TbNodeUtilsTest {
ObjectNode node = JacksonUtil.newObjectNode();
node.set("key1", key1Node);
TbMsg msg = TbMsg.newMsg("CUSTOM", TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node));
TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node));
String result = TbNodeUtils.processPattern(pattern, msg);
Assert.assertEquals("ABC metadata_value value3", result);
}
@ -113,7 +114,7 @@ public class TbNodeUtilsTest {
ObjectNode node = JacksonUtil.newObjectNode();
node.set("key1", key1Node);
TbMsg msg = TbMsg.newMsg("CUSTOM", TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node));
TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node));
String result = TbNodeUtils.processPattern(pattern, msg);
Assert.assertEquals("ABC metadata_value $[key1.key2[0].key3]", result);
}

20
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java

@ -26,6 +26,8 @@ import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.script.ScriptLanguage;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -55,13 +57,13 @@ public abstract class TbAbstractAlarmNode<C extends TbAbstractAlarmNodeConfigura
withCallback(processAlarm(ctx, msg),
alarmResult -> {
if (alarmResult.alarm == null) {
ctx.tellNext(msg, "False");
ctx.tellNext(msg, TbNodeConnectionType.FALSE);
} else if (alarmResult.isCreated) {
tellNext(ctx, msg, alarmResult, DataConstants.ENTITY_CREATED, "Created");
tellNext(ctx, msg, alarmResult, TbMsgType.ENTITY_CREATED, "Created");
} else if (alarmResult.isUpdated) {
tellNext(ctx, msg, alarmResult, DataConstants.ENTITY_UPDATED, "Updated");
tellNext(ctx, msg, alarmResult, TbMsgType.ENTITY_UPDATED, "Updated");
} else if (alarmResult.isCleared) {
tellNext(ctx, msg, alarmResult, DataConstants.ALARM_CLEAR, "Cleared");
tellNext(ctx, msg, alarmResult, TbMsgType.ALARM_CLEAR, "Cleared");
} else {
ctx.tellSuccess(msg);
}
@ -71,13 +73,13 @@ public abstract class TbAbstractAlarmNode<C extends TbAbstractAlarmNodeConfigura
protected abstract ListenableFuture<TbAlarmResult> processAlarm(TbContext ctx, TbMsg msg);
protected ListenableFuture<JsonNode> buildAlarmDetails(TbContext ctx, TbMsg msg, JsonNode previousDetails) {
protected ListenableFuture<JsonNode> buildAlarmDetails(TbMsg msg, JsonNode previousDetails) {
try {
TbMsg dummyMsg = msg;
if (previousDetails != null) {
TbMsgMetaData metaData = msg.getMetaData().copy();
metaData.putValue(PREV_ALARM_DETAILS, JacksonUtil.toString(previousDetails));
dummyMsg = ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), metaData, msg.getData());
dummyMsg = TbMsg.transformMsgMetadata(msg, metaData);
}
return scriptEngine.executeJsonAsync(dummyMsg);
} catch (Exception e) {
@ -96,7 +98,7 @@ public abstract class TbAbstractAlarmNode<C extends TbAbstractAlarmNodeConfigura
} else if (alarmResult.isCleared) {
metaData.putValue(DataConstants.IS_CLEARED_ALARM, Boolean.TRUE.toString());
}
return ctx.transformMsg(originalMsg, "ALARM", originalMsg.getOriginator(), metaData, data);
return ctx.transformMsg(originalMsg, TbMsgType.ALARM, originalMsg.getOriginator(), metaData, data);
}
@Override
@ -106,8 +108,8 @@ public abstract class TbAbstractAlarmNode<C extends TbAbstractAlarmNodeConfigura
}
}
private void tellNext(TbContext ctx, TbMsg msg, TbAlarmResult alarmResult, String entityAction, String alarmAction) {
ctx.enqueue(ctx.alarmActionMsg(alarmResult.alarm, ctx.getSelfId(), entityAction),
private void tellNext(TbContext ctx, TbMsg msg, TbAlarmResult alarmResult, TbMsgType actionMsgType, String alarmAction) {
ctx.enqueue(ctx.alarmActionMsg(alarmResult.alarm, ctx.getSelfId(), actionMsgType),
() -> ctx.tellNext(toAlarmMsg(ctx, alarmResult, msg), alarmAction),
throwable -> ctx.tellFailure(toAlarmMsg(ctx, alarmResult, msg), throwable));
}

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java

@ -57,8 +57,8 @@ import java.util.Optional;
import java.util.concurrent.TimeUnit;
import static org.thingsboard.common.util.DonAsynchron.withCallback;
import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE;
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.FAILURE;
import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.SUCCESS;
@Slf4j
public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationActionNodeConfiguration> implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java

@ -71,7 +71,7 @@ public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfig
private ListenableFuture<TbAlarmResult> clearAlarm(TbContext ctx, TbMsg msg, Alarm alarm) {
ctx.logJsEvalRequest();
ListenableFuture<JsonNode> asyncDetails = buildAlarmDetails(ctx, msg, alarm.getDetails());
ListenableFuture<JsonNode> asyncDetails = buildAlarmDetails(msg, alarm.getDetails());
return Futures.transform(asyncDetails, details -> {
ctx.logJsEvalResponse();
AlarmApiCallResult result = ctx.getAlarmService().clearAlarm(ctx.getTenantId(), alarm.getId(), System.currentTimeMillis(), details);

23
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java

@ -36,7 +36,6 @@ import org.thingsboard.server.common.data.objects.AttributesEntityView;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.util.CollectionsUtil;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import javax.annotation.Nullable;
@ -45,7 +44,12 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT;
import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED;
import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED;
import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT;
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST;
import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.SUCCESS;
@Slf4j
@RuleNode(
@ -71,14 +75,11 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
if (DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType()) ||
DataConstants.ATTRIBUTES_DELETED.equals(msg.getType()) ||
DataConstants.ACTIVITY_EVENT.equals(msg.getType()) ||
DataConstants.INACTIVITY_EVENT.equals(msg.getType()) ||
SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType())) {
if (msg.isTypeOneOf(ATTRIBUTES_UPDATED, ATTRIBUTES_DELETED,
ACTIVITY_EVENT, INACTIVITY_EVENT, POST_ATTRIBUTES_REQUEST)) {
if (!msg.getMetaData().getData().isEmpty()) {
long now = System.currentTimeMillis();
String scope = msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ?
String scope = msg.isTypeOf(POST_ATTRIBUTES_REQUEST) ?
DataConstants.CLIENT_SCOPE : msg.getMetaData().getValue(DataConstants.SCOPE);
ListenableFuture<List<EntityView>> entityViewsFuture =
@ -90,9 +91,9 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
long startTime = entityView.getStartTimeMs();
long endTime = entityView.getEndTimeMs();
if ((endTime != 0 && endTime > now && startTime < now) || (endTime == 0 && startTime < now)) {
if (DataConstants.ATTRIBUTES_DELETED.equals(msg.getType())) {
if (msg.isTypeOf(ATTRIBUTES_DELETED)) {
List<String> attributes = new ArrayList<>();
for (JsonElement element : new JsonParser().parse(msg.getData()).getAsJsonObject().get("attributes").getAsJsonArray()) {
for (JsonElement element : JsonParser.parseString(msg.getData()).getAsJsonObject().get("attributes").getAsJsonArray()) {
if (element.isJsonPrimitive()) {
JsonPrimitive value = element.getAsJsonPrimitive();
if (value.isString()) {
@ -107,7 +108,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
getFutureCallback(ctx, msg, entityView));
}
} else {
Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData()));
Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(JsonParser.parseString(msg.getData()));
List<AttributeKvEntry> filteredAttributes =
attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr.getKey(), entityView)).collect(Collectors.toList());
ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), entityView.getId(), scope, filteredAttributes,

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java

@ -120,7 +120,7 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConf
boolean buildDetails = !config.isUseMessageAlarmData() || config.isOverwriteAlarmDetails();
if (buildDetails) {
ctx.logJsEvalRequest();
asyncDetails = buildAlarmDetails(ctx, msg, null);
asyncDetails = buildAlarmDetails(msg, null);
} else {
asyncDetails = Futures.immediateFuture(null);
}
@ -149,7 +149,7 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConf
boolean buildDetails = !config.isUseMessageAlarmData() || config.isOverwriteAlarmDetails();
if (buildDetails) {
ctx.logJsEvalRequest();
asyncDetails = buildAlarmDetails(ctx, msg, existingAlarm.getDetails());
asyncDetails = buildAlarmDetails(msg, existingAlarm.getDetails());
} else {
asyncDetails = Futures.immediateFuture(null);
}

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java

@ -75,7 +75,7 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateR
ListenableFuture<Boolean> future = createRelationIfAbsent(ctx, msg, entity, relationType);
return Futures.transform(future, result -> {
if (result && config.isChangeOriginatorToRelatedEntity()) {
TbMsg tbMsg = ctx.transformMsg(msg, msg.getType(), entity.getEntityId(), msg.getMetaData(), msg.getData());
TbMsg tbMsg = ctx.transformMsgOriginator(msg, entity.getEntityId());
return new RelationContainer(tbMsg, result);
}
return new RelationContainer(msg, result);

15
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java

@ -24,17 +24,16 @@ import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
@ -48,8 +47,6 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
)
public class TbMsgCountNode implements TbNode {
private static final String TB_MSG_COUNT_NODE_MSG = "TbMsgCountNodeMsg";
private AtomicLong messagesProcessed = new AtomicLong(0);
private final Gson gson = new Gson();
private UUID nextTickId;
@ -68,7 +65,7 @@ public class TbMsgCountNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
if (msg.getType().equals(TB_MSG_COUNT_NODE_MSG) && msg.getId().equals(nextTickId)) {
if (msg.isTypeOf(TbMsgType.MSG_COUNT_SELF_MSG) && msg.getId().equals(nextTickId)) {
JsonObject telemetryJson = new JsonObject();
telemetryJson.addProperty(this.telemetryPrefix + "_" + ctx.getServiceId(), messagesProcessed.longValue());
@ -77,8 +74,8 @@ public class TbMsgCountNode implements TbNode {
TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue("delta", Long.toString(System.currentTimeMillis() - lastScheduledTs + delay));
TbMsg tbMsg = TbMsg.newMsg(msg.getQueueName(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), ctx.getTenantId(), msg.getCustomerId(), metaData, gson.toJson(telemetryJson));
ctx.enqueueForTellNext(tbMsg, SUCCESS);
TbMsg tbMsg = TbMsg.newMsg(msg.getQueueName(), TbMsgType.POST_TELEMETRY_REQUEST, ctx.getTenantId(), msg.getCustomerId(), metaData, gson.toJson(telemetryJson));
ctx.enqueueForTellNext(tbMsg, TbNodeConnectionType.SUCCESS);
scheduleTickMsg(ctx, tbMsg);
} else {
messagesProcessed.incrementAndGet();
@ -93,7 +90,7 @@ public class TbMsgCountNode implements TbNode {
}
lastScheduledTs = lastScheduledTs + delay;
long curDelay = Math.max(0L, (lastScheduledTs - curTs));
TbMsg tickMsg = ctx.newMsg(null, TB_MSG_COUNT_NODE_MSG, ctx.getSelfId(), msg != null ? msg.getCustomerId() : null, new TbMsgMetaData(), "");
TbMsg tickMsg = ctx.newMsg(null, TbMsgType.MSG_COUNT_SELF_MSG, ctx.getSelfId(), msg != null ? msg.getCustomerId() : null, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING);
nextTickId = tickMsg.getId();
ctx.tellSelf(tickMsg, curDelay);
}

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java

@ -29,7 +29,6 @@ import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.external.TbAbstractExternalNode;
import org.thingsboard.server.common.data.plugin.ComponentType;
@ -106,13 +105,13 @@ public class TbSnsNode extends TbAbstractExternalNode {
TbMsgMetaData metaData = origMsg.getMetaData().copy();
metaData.putValue(MESSAGE_ID, result.getMessageId());
metaData.putValue(REQUEST_ID, result.getSdkResponseMetadata().getRequestId());
return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData());
return TbMsg.transformMsgMetadata(origMsg, metaData);
}
private TbMsg processException(TbContext ctx, TbMsg origMsg, Throwable t) {
TbMsgMetaData metaData = origMsg.getMetaData().copy();
metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage());
return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData());
return TbMsg.transformMsgMetadata(origMsg, metaData);
}
@Override

17
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java

@ -28,7 +28,6 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
@ -93,14 +92,14 @@ public class TbSqsNode extends TbAbstractExternalNode {
var tbMsg = ackIfNeeded(ctx, msg);
withCallback(publishMessageAsync(ctx, tbMsg),
m -> tellSuccess(ctx, m),
t -> tellFailure(ctx, processException(ctx, tbMsg, t), t));
t -> tellFailure(ctx, processException(tbMsg, t), t));
}
private ListenableFuture<TbMsg> publishMessageAsync(TbContext ctx, TbMsg msg) {
return ctx.getExternalCallExecutor().executeAsync(() -> publishMessage(ctx, msg));
return ctx.getExternalCallExecutor().executeAsync(() -> publishMessage(msg));
}
private TbMsg publishMessage(TbContext ctx, TbMsg msg) {
private TbMsg publishMessage(TbMsg msg) {
String queueUrl = TbNodeUtils.processPattern(this.config.getQueueUrlPattern(), msg);
SendMessageRequest sendMsgRequest = new SendMessageRequest();
sendMsgRequest.withQueueUrl(queueUrl);
@ -119,10 +118,10 @@ public class TbSqsNode extends TbAbstractExternalNode {
sendMsgRequest.withMessageGroupId(msg.getOriginator().toString());
}
SendMessageResult result = this.sqsClient.sendMessage(sendMsgRequest);
return processSendMessageResult(ctx, msg, result);
return processSendMessageResult(msg, result);
}
private TbMsg processSendMessageResult(TbContext ctx, TbMsg origMsg, SendMessageResult result) {
private TbMsg processSendMessageResult(TbMsg origMsg, SendMessageResult result) {
TbMsgMetaData metaData = origMsg.getMetaData().copy();
metaData.putValue(MESSAGE_ID, result.getMessageId());
metaData.putValue(REQUEST_ID, result.getSdkResponseMetadata().getRequestId());
@ -135,13 +134,13 @@ public class TbSqsNode extends TbAbstractExternalNode {
if (!StringUtils.isEmpty(result.getSequenceNumber())) {
metaData.putValue(SEQUENCE_NUMBER, result.getSequenceNumber());
}
return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData());
return TbMsg.transformMsgMetadata(origMsg, metaData);
}
private TbMsg processException(TbContext ctx, TbMsg origMsg, Throwable t) {
private TbMsg processException(TbMsg origMsg, Throwable t) {
TbMsgMetaData metaData = origMsg.getMetaData().copy();
metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage());
return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData());
return TbMsg.transformMsgMetadata(origMsg, metaData);
}
@Override

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

@ -28,8 +28,11 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.script.ScriptLanguage;
import org.thingsboard.server.common.msg.TbMsg;
@ -41,7 +44,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.thingsboard.common.util.DonAsynchron.withCallback;
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
@Slf4j
@RuleNode(
@ -58,8 +60,6 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
public class TbMsgGeneratorNode implements TbNode {
private static final String TB_MSG_GENERATOR_NODE_MSG = "TbMsgGeneratorNodeMsg";
private TbMsgGeneratorNodeConfiguration config;
private ScriptEngine scriptEngine;
private long delay;
@ -97,7 +97,7 @@ public class TbMsgGeneratorNode implements TbNode {
if (initialized.compareAndSet(false, true)) {
this.scriptEngine = ctx.createScriptEngine(config.getScriptLang(),
ScriptLanguage.TBEL.equals(config.getScriptLang()) ? config.getTbelScript() : config.getJsScript(), "prevMsg", "prevMetadata", "prevMsgType");
scheduleTickMsg(ctx);
scheduleTickMsg(ctx, null);
}
} else if (initialized.compareAndSet(true, false)) {
destroy();
@ -107,14 +107,14 @@ public class TbMsgGeneratorNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
log.trace("onMsg, config {}, msg {}", config, msg);
if (initialized.get() && msg.getType().equals(TB_MSG_GENERATOR_NODE_MSG) && msg.getId().equals(nextTickId)) {
if (initialized.get() && msg.isTypeOf(TbMsgType.GENERATOR_NODE_SELF_MSG) && msg.getId().equals(nextTickId)) {
TbStopWatch sw = TbStopWatch.create();
withCallback(generate(ctx, msg),
m -> {
log.trace("onMsg onSuccess callback, took {}ms, config {}, msg {}", sw.stopAndGetTotalTimeMillis(), config, msg);
if (initialized.get() && (config.getMsgCount() == TbMsgGeneratorNodeConfiguration.UNLIMITED_MSG_COUNT || currentMsgCount < config.getMsgCount())) {
ctx.enqueueForTellNext(m, SUCCESS);
scheduleTickMsg(ctx);
ctx.enqueueForTellNext(m, TbNodeConnectionType.SUCCESS);
scheduleTickMsg(ctx, msg);
currentMsgCount++;
}
},
@ -122,14 +122,14 @@ public class TbMsgGeneratorNode implements TbNode {
log.trace("onMsg onFailure callback, took {}ms, config {}, msg {}", sw.stopAndGetTotalTimeMillis(), config, msg, t);
if (initialized.get() && (config.getMsgCount() == TbMsgGeneratorNodeConfiguration.UNLIMITED_MSG_COUNT || currentMsgCount < config.getMsgCount())) {
ctx.tellFailure(msg, t);
scheduleTickMsg(ctx);
scheduleTickMsg(ctx, msg);
currentMsgCount++;
}
});
}
}
private void scheduleTickMsg(TbContext ctx) {
private void scheduleTickMsg(TbContext ctx, TbMsg msg) {
log.trace("scheduleTickMsg, config {}", config);
long curTs = System.currentTimeMillis();
if (lastScheduledTs == 0L) {
@ -137,7 +137,8 @@ public class TbMsgGeneratorNode implements TbNode {
}
lastScheduledTs = lastScheduledTs + delay;
long curDelay = Math.max(0L, (lastScheduledTs - curTs));
TbMsg tickMsg = ctx.newMsg(config.getQueueName(), TB_MSG_GENERATOR_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), "");
TbMsg tickMsg = ctx.newMsg(config.getQueueName(), TbMsgType.GENERATOR_NODE_SELF_MSG, ctx.getSelfId(),
getCustomerIdFromMsg(msg), TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING);
nextTickId = tickMsg.getId();
ctx.tellSelf(tickMsg, curDelay);
}
@ -145,7 +146,7 @@ public class TbMsgGeneratorNode implements TbNode {
private ListenableFuture<TbMsg> generate(TbContext ctx, TbMsg msg) {
log.trace("generate, config {}", config);
if (prevMsg == null) {
prevMsg = ctx.newMsg(config.getQueueName(), "", originatorId, msg.getCustomerId(), new TbMsgMetaData(), "{}");
prevMsg = ctx.newMsg(config.getQueueName(), TbMsg.EMPTY_STRING, originatorId, msg.getCustomerId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT);
}
if (initialized.get()) {
ctx.logJsEvalRequest();
@ -160,6 +161,10 @@ public class TbMsgGeneratorNode implements TbNode {
}
private CustomerId getCustomerIdFromMsg(TbMsg msg) {
return msg != null ? msg.getCustomerId() : null;
}
@Override
public void destroy() {
log.trace("destroy, config {}", config);

12
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java

@ -24,9 +24,10 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.util.TbPair;
import org.thingsboard.server.common.msg.TbMsg;
@ -60,10 +61,7 @@ import java.util.concurrent.TimeUnit;
@Slf4j
public class TbMsgDeduplicationNode implements TbNode {
private static final String TB_MSG_DEDUPLICATION_TIMEOUT_MSG = "TbMsgDeduplicationNodeMsg";
public static final int TB_MSG_DEDUPLICATION_RETRY_DELAY = 10;
private static final String EMPTY_DATA = "";
private static final TbMsgMetaData EMPTY_META_DATA = new TbMsgMetaData();
private TbMsgDeduplicationNodeConfiguration config;
@ -82,7 +80,7 @@ public class TbMsgDeduplicationNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
if (TB_MSG_DEDUPLICATION_TIMEOUT_MSG.equals(msg.getType())) {
if (msg.isTypeOf(TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG)) {
processDeduplication(ctx, msg.getOriginator());
} else {
processOnRegularMsg(ctx, msg);
@ -196,7 +194,7 @@ public class TbMsgDeduplicationNode implements TbNode {
private void enqueueForTellNextWithRetry(TbContext ctx, TbMsg msg, int retryAttempt) {
if (config.getMaxRetries() > retryAttempt) {
ctx.enqueueForTellNext(msg, TbRelationTypes.SUCCESS,
ctx.enqueueForTellNext(msg, TbNodeConnectionType.SUCCESS,
() -> {
log.trace("[{}][{}][{}] Successfully enqueue deduplication result message!", ctx.getSelfId(), msg.getOriginator(), retryAttempt);
},
@ -210,7 +208,7 @@ public class TbMsgDeduplicationNode implements TbNode {
}
private void scheduleTickMsg(TbContext ctx, EntityId deduplicationId) {
ctx.tellSelf(ctx.newMsg(null, TB_MSG_DEDUPLICATION_TIMEOUT_MSG, deduplicationId, EMPTY_META_DATA, EMPTY_DATA), deduplicationInterval + 1);
ctx.tellSelf(ctx.newMsg(null, TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG, deduplicationId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING), deduplicationInterval + 1);
}
private String getMergedData(List<TbMsg> msgs) {

12
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java

@ -23,6 +23,8 @@ import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -32,8 +34,6 @@ import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
@ -50,8 +50,6 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
)
public class TbMsgDelayNode implements TbNode {
private static final String TB_MSG_DELAY_NODE_MSG = "TbMsgDelayNodeMsg";
private TbMsgDelayNodeConfiguration config;
private Map<UUID, TbMsg> pendingMsgs;
@ -63,7 +61,7 @@ public class TbMsgDelayNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
if (msg.getType().equals(TB_MSG_DELAY_NODE_MSG)) {
if (msg.isTypeOf(TbMsgType.DELAY_TIMEOUT_SELF_MSG)) {
TbMsg pendingMsg = pendingMsgs.remove(UUID.fromString(msg.getData()));
if (pendingMsg != null) {
ctx.enqueueForTellNext(
@ -75,13 +73,13 @@ public class TbMsgDelayNode implements TbNode {
pendingMsg.getMetaData(),
pendingMsg.getData()
),
SUCCESS
TbNodeConnectionType.SUCCESS
);
}
} else {
if (pendingMsgs.size() < config.getMaxPendingMsgs()) {
pendingMsgs.put(msg.getId(), msg);
TbMsg tickMsg = ctx.newMsg(null, TB_MSG_DELAY_NODE_MSG, ctx.getSelfId(), msg.getCustomerId(), new TbMsgMetaData(), msg.getId().toString());
TbMsg tickMsg = ctx.newMsg(null, TbMsgType.DELAY_TIMEOUT_SELF_MSG, ctx.getSelfId(), msg.getCustomerId(), TbMsgMetaData.EMPTY, msg.getId().toString());
ctx.tellSelf(tickMsg, getDelay(msg));
ctx.ack(msg);
} else {

63
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java

@ -30,13 +30,23 @@ import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT;
import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM;
import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED;
import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED;
import static org.thingsboard.server.common.data.msg.TbMsgType.CONNECT_EVENT;
import static org.thingsboard.server.common.data.msg.TbMsgType.DISCONNECT_EVENT;
import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT;
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST;
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST;
import static org.thingsboard.server.common.data.msg.TbMsgType.TIMESERIES_UPDATED;
@Slf4j
public abstract class AbstractTbMsgPushNode<T extends BaseTbMsgPushNodeConfiguration, S, U> implements TbNode {
@ -57,7 +67,7 @@ public abstract class AbstractTbMsgPushNode<T extends BaseTbMsgPushNodeConfigura
return;
}
if (isSupportedOriginator(msg.getOriginator().getEntityType())) {
if (isSupportedMsgType(msg.getType())) {
if (isSupportedMsgType(msg)) {
processMsg(ctx, msg);
} else {
String errMsg = String.format("Unsupported msg type %s", msg.getType());
@ -72,13 +82,12 @@ public abstract class AbstractTbMsgPushNode<T extends BaseTbMsgPushNodeConfigura
}
protected S buildEvent(TbMsg msg, TbContext ctx) {
String msgType = msg.getType();
if (DataConstants.ALARM.equals(msgType)) {
if (msg.isTypeOf(ALARM)) {
EdgeEventActionType actionType = getAlarmActionType(msg);
return buildEvent(ctx.getTenantId(), actionType, getUUIDFromMsgData(msg), getAlarmEventType(), null);
} else {
Map<String, String> metadata = msg.getMetaData().getData();
EdgeEventActionType actionType = getEdgeEventActionTypeByMsgType(msgType, metadata);
EdgeEventActionType actionType = getEdgeEventActionTypeByMsgType(msg);
Map<String, Object> entityBody = new HashMap<>();
JsonNode dataJson = JacksonUtil.toJsonNode(msg.getData());
switch (actionType) {
@ -148,45 +157,31 @@ public abstract class AbstractTbMsgPushNode<T extends BaseTbMsgPushNodeConfigura
return scope;
}
protected EdgeEventActionType getEdgeEventActionTypeByMsgType(String msgType, Map<String, String> metadata) {
protected EdgeEventActionType getEdgeEventActionTypeByMsgType(TbMsg msg) {
EdgeEventActionType actionType;
if (SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msgType)
|| DataConstants.TIMESERIES_UPDATED.equals(msgType)) {
if (msg.isTypeOneOf(POST_TELEMETRY_REQUEST, TIMESERIES_UPDATED)) {
actionType = EdgeEventActionType.TIMESERIES_UPDATED;
} else if (DataConstants.ATTRIBUTES_UPDATED.equals(msgType)) {
} else if (msg.isTypeOf(ATTRIBUTES_UPDATED)) {
actionType = EdgeEventActionType.ATTRIBUTES_UPDATED;
} else if (SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msgType)) {
} else if (msg.isTypeOf(POST_ATTRIBUTES_REQUEST)) {
actionType = EdgeEventActionType.POST_ATTRIBUTES;
} else if (DataConstants.ATTRIBUTES_DELETED.equals(msgType)) {
} else if (msg.isTypeOf(ATTRIBUTES_DELETED)) {
actionType = EdgeEventActionType.ATTRIBUTES_DELETED;
} else if (DataConstants.CONNECT_EVENT.equals(msgType)
|| DataConstants.DISCONNECT_EVENT.equals(msgType)
|| DataConstants.ACTIVITY_EVENT.equals(msgType)
|| DataConstants.INACTIVITY_EVENT.equals(msgType)) {
String scope = metadata.get(SCOPE);
if ( StringUtils.isEmpty(scope)) {
actionType = EdgeEventActionType.TIMESERIES_UPDATED;
} else {
actionType = EdgeEventActionType.ATTRIBUTES_UPDATED;
}
} else if (msg.isTypeOneOf(CONNECT_EVENT, DISCONNECT_EVENT, ACTIVITY_EVENT, INACTIVITY_EVENT)) {
String scope = msg.getMetaData().getValue(SCOPE);
actionType = StringUtils.isEmpty(scope) ?
EdgeEventActionType.TIMESERIES_UPDATED : EdgeEventActionType.ATTRIBUTES_UPDATED;
} else {
log.warn("Unsupported msg type [{}]", msgType);
throw new IllegalArgumentException("Unsupported msg type: " + msgType);
String type = msg.getType();
log.warn("Unsupported msg type [{}]", type);
throw new IllegalArgumentException("Unsupported msg type: " + type);
}
return actionType;
}
protected boolean isSupportedMsgType(String msgType) {
return SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msgType)
|| SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msgType)
|| DataConstants.ATTRIBUTES_UPDATED.equals(msgType)
|| DataConstants.ATTRIBUTES_DELETED.equals(msgType)
|| DataConstants.TIMESERIES_UPDATED.equals(msgType)
|| DataConstants.ALARM.equals(msgType)
|| DataConstants.CONNECT_EVENT.equals(msgType)
|| DataConstants.DISCONNECT_EVENT.equals(msgType)
|| DataConstants.ACTIVITY_EVENT.equals(msgType)
|| DataConstants.INACTIVITY_EVENT.equals(msgType);
protected boolean isSupportedMsgType(TbMsg msg) {
return msg.isTypeOneOf(POST_TELEMETRY_REQUEST, POST_ATTRIBUTES_REQUEST, ATTRIBUTES_UPDATED,
ATTRIBUTES_DELETED, TIMESERIES_UPDATED, ALARM, CONNECT_EVENT, DISCONNECT_EVENT, ACTIVITY_EVENT, INACTIVITY_EVENT);
}
protected boolean isSupportedOriginator(EntityType entityType) {

8
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java

@ -17,7 +17,7 @@ package org.thingsboard.rule.engine.external;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.msg.TbMsg;
public abstract class TbAbstractExternalNode implements TbNode {
@ -30,7 +30,7 @@ public abstract class TbAbstractExternalNode implements TbNode {
protected void tellSuccess(TbContext ctx, TbMsg tbMsg) {
if (forceAck) {
ctx.enqueueForTellNext(tbMsg.copyWithNewCtx(), TbRelationTypes.SUCCESS);
ctx.enqueueForTellNext(tbMsg.copyWithNewCtx(), TbNodeConnectionType.SUCCESS);
} else {
ctx.tellSuccess(tbMsg);
}
@ -39,13 +39,13 @@ public abstract class TbAbstractExternalNode implements TbNode {
protected void tellFailure(TbContext ctx, TbMsg tbMsg, Throwable t) {
if (forceAck) {
if (t == null) {
ctx.enqueueForTellNext(tbMsg.copyWithNewCtx(), TbRelationTypes.FAILURE);
ctx.enqueueForTellNext(tbMsg.copyWithNewCtx(), TbNodeConnectionType.FAILURE);
} else {
ctx.enqueueForTellFailure(tbMsg.copyWithNewCtx(), t);
}
} else {
if (t == null) {
ctx.tellNext(tbMsg, TbRelationTypes.FAILURE);
ctx.tellNext(tbMsg, TbNodeConnectionType.FAILURE);
} else {
ctx.tellFailure(tbMsg, t);
}

8
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java

@ -31,10 +31,11 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
type = ComponentType.FILTER,
name = "asset profile switch",
customRelations = true,
relationTypes = {},
relationTypes = {"default"},
configClazz = EmptyNodeConfiguration.class,
nodeDescription = "Route incoming messages based on the name of the asset profile",
nodeDetails = "Route incoming messages based on the name of the asset profile. The asset profile name is case-sensitive",
nodeDetails = "Route incoming messages based on the name of the asset profile. The asset profile name is case-sensitive.<br><br>" +
"Output connections: <i>Asset profile name</i> or <code>Failure</code>",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig")
public class TbAssetTypeSwitchNode extends TbAbstractTypeSwitchNode {
@ -42,7 +43,8 @@ public class TbAssetTypeSwitchNode extends TbAbstractTypeSwitchNode {
@Override
protected String getRelationType(TbContext ctx, EntityId originator) throws TbNodeException {
if (!EntityType.ASSET.equals(originator.getEntityType())) {
throw new TbNodeException("Unsupported originator type: " + originator.getEntityType() + "! Only 'ASSET' type is allowed.");
throw new TbNodeException("Unsupported originator type: " + originator.getEntityType().getNormalName() + "!" +
" Only " + EntityType.ASSET.getNormalName() + " type is allowed.");
}
AssetProfile assetProfile = ctx.getAssetProfileCache().get(ctx.getTenantId(), (AssetId) originator);
if (assetProfile == null) {

37
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.filter;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleNode;
@ -28,24 +27,25 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
import javax.annotation.Nullable;
import java.io.IOException;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "check alarm status",
name = "alarm status filter",
configClazz = TbCheckAlarmStatusNodeConfig.class,
relationTypes = {"True", "False"},
relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE},
nodeDescription = "Checks alarm status.",
nodeDetails = "Checks the alarm status to match one of the specified statuses.",
nodeDetails = "Checks the alarm status to match one of the specified statuses.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeCheckAlarmStatusConfig")
public class TbCheckAlarmStatusNode implements TbNode {
private TbCheckAlarmStatusNodeConfig config;
@Override
@ -60,33 +60,24 @@ public class TbCheckAlarmStatusNode implements TbNode {
ListenableFuture<Alarm> latest = ctx.getAlarmService().findAlarmByIdAsync(ctx.getTenantId(), alarm.getId());
Futures.addCallback(latest, new FutureCallback<Alarm>() {
Futures.addCallback(latest, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable Alarm result) {
if (result != null) {
boolean isPresent = false;
for (AlarmStatus alarmStatus : config.getAlarmStatusList()) {
if (result.getStatus() == alarmStatus) {
isPresent = true;
break;
}
}
if (isPresent) {
ctx.tellNext(msg, "True");
} else {
ctx.tellNext(msg, "False");
}
} else {
if (result == null) {
ctx.tellFailure(msg, new TbNodeException("No such alarm found."));
return;
}
boolean isPresent = config.getAlarmStatusList().stream()
.anyMatch(alarmStatus -> result.getStatus() == alarmStatus);
ctx.tellNext(msg, isPresent ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE);
}
@Override
public void onFailure(Throwable t) {
ctx.tellFailure(msg, t);
}
}, MoreExecutors.directExecutor());
} catch (IllegalArgumentException e) {
}, ctx.getDbCallbackExecutor());
} catch (Exception e) {
log.error("Failed to parse alarm: [{}]", msg.getData());
throw new TbNodeException(e);
}

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeConfig.java

@ -24,12 +24,14 @@ import java.util.List;
@Data
public class TbCheckAlarmStatusNodeConfig implements NodeConfiguration<TbCheckAlarmStatusNodeConfig> {
private List<AlarmStatus> alarmStatusList;
@Override
public TbCheckAlarmStatusNodeConfig defaultConfiguration() {
TbCheckAlarmStatusNodeConfig config = new TbCheckAlarmStatusNodeConfig();
var config = new TbCheckAlarmStatusNodeConfig();
config.setAlarmStatusList(Arrays.asList(AlarmStatus.ACTIVE_ACK, AlarmStatus.ACTIVE_UNACK));
return config;
}
}

18
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java

@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@ -33,12 +34,12 @@ import java.util.Map;
@RuleNode(
type = ComponentType.FILTER,
name = "check fields presence",
relationTypes = {"True", "False"},
relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE},
configClazz = TbCheckMessageNodeConfiguration.class,
nodeDescription = "Checks the presence of the specified fields in the message and/or metadata.",
nodeDetails = "Checks the presence of the specified fields in the message and/or metadata. " +
"By default, the rule node checks that all specified fields need to be present. " +
"Uncheck the 'Check that all specified fields are present' if the presence of at least one field is sufficient.",
nodeDetails = "By default, the rule node checks that all specified fields are present. " +
"Uncheck the 'Check that all selected fields are present' if the presence of at least one field is sufficient.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeCheckMessageConfig")
public class TbCheckMessageNode implements TbNode {
@ -59,11 +60,10 @@ public class TbCheckMessageNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
try {
if (config.isCheckAllKeys()) {
ctx.tellNext(msg, allKeysData(msg) && allKeysMetadata(msg) ? "True" : "False");
} else {
ctx.tellNext(msg, atLeastOneData(msg) || atLeastOneMetadata(msg) ? "True" : "False");
}
String relationType = config.isCheckAllKeys() ?
allKeysData(msg) && allKeysMetadata(msg) ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE :
atLeastOneData(msg) || atLeastOneMetadata(msg) ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE;
ctx.tellNext(msg, relationType);
} catch (Exception e) {
ctx.tellFailure(msg, e);
}

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

@ -22,7 +22,7 @@ import java.util.Collections;
import java.util.List;
@Data
public class TbCheckMessageNodeConfiguration implements NodeConfiguration {
public class TbCheckMessageNodeConfiguration implements NodeConfiguration<TbCheckMessageNodeConfiguration> {
private List<String> messageNames;
private List<String> metadataNames;

80
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java

@ -15,22 +15,26 @@
*/
package org.thingsboard.rule.engine.filter;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.TbVersionedNode;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.util.TbPair;
import org.thingsboard.server.common.msg.TbMsg;
import java.util.List;
@ -43,15 +47,20 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "check relation",
name = "check relation presence",
configClazz = TbCheckRelationNodeConfiguration.class,
relationTypes = {"True", "False"},
version = 1,
relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE},
nodeDescription = "Checks the presence of the relation between the originator of the message and other entities.",
nodeDetails = "If 'check relation to specific entity' is selected, one must specify a related entity. " +
"Otherwise, the rule node checks the presence of a relation to any entity that matches the direction and relation type criteria.",
nodeDetails = "If 'check relation to specific entity' is selected, you should specify a related entity. " +
"Otherwise, the rule node checks the presence of a relation to any entity. " +
"In both cases, relation lookup is based on configured direction and type.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeCheckRelationConfig")
public class TbCheckRelationNode implements TbNode {
public class TbCheckRelationNode implements TbVersionedNode {
private static final String DIRECTION_PROPERTY_NAME = "direction";
private TbCheckRelationNodeConfiguration config;
private EntityId singleEntityId;
@ -60,6 +69,9 @@ public class TbCheckRelationNode implements TbNode {
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbCheckRelationNodeConfiguration.class);
if (config.isCheckForSingleEntity()) {
if (StringUtils.isEmpty(config.getEntityType()) || StringUtils.isEmpty(config.getEntityId())) {
throw new TbNodeException("Entity should be specified!");
}
this.singleEntityId = EntityIdFactory.getByTypeAndId(config.getEntityType(), config.getEntityId());
ctx.checkTenantEntity(singleEntityId);
}
@ -67,44 +79,56 @@ public class TbCheckRelationNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
ListenableFuture<Boolean> checkRelationFuture;
if (config.isCheckForSingleEntity()) {
checkRelationFuture = processSingle(ctx, msg);
} else {
checkRelationFuture = processList(ctx, msg);
}
withCallback(checkRelationFuture, filterResult -> ctx.tellNext(msg, filterResult ? "True" : "False"), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor());
ListenableFuture<Boolean> checkRelationFuture = config.isCheckForSingleEntity() ?
processSingle(ctx, msg) : processList(ctx, msg);
withCallback(checkRelationFuture,
filterResult -> ctx.tellNext(msg, filterResult ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE),
t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor());
}
private ListenableFuture<Boolean> processSingle(TbContext ctx, TbMsg msg) {
EntityId from;
EntityId to;
if (EntitySearchDirection.FROM.name().equals(config.getDirection())) {
from = singleEntityId;
to = msg.getOriginator();
} else {
to = singleEntityId;
from = msg.getOriginator();
} else {
from = singleEntityId;
to = msg.getOriginator();
}
return ctx.getRelationService().checkRelationAsync(ctx.getTenantId(), from, to, config.getRelationType(), RelationTypeGroup.COMMON);
}
private ListenableFuture<Boolean> processList(TbContext ctx, TbMsg msg) {
if (EntitySearchDirection.FROM.name().equals(config.getDirection())) {
return Futures.transformAsync(ctx.getRelationService()
.findByToAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON), this::isEmptyList, MoreExecutors.directExecutor());
} else {
return Futures.transformAsync(ctx.getRelationService()
.findByFromAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON), this::isEmptyList, MoreExecutors.directExecutor());
}
ListenableFuture<List<EntityRelation>> relationListFuture = EntitySearchDirection.FROM.name().equals(config.getDirection()) ?
ctx.getRelationService().findByFromAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON) :
ctx.getRelationService().findByToAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON);
return Futures.transformAsync(relationListFuture, this::isEmptyList, ctx.getDbCallbackExecutor());
}
private ListenableFuture<Boolean> isEmptyList(List<EntityRelation> entityRelations) {
if (entityRelations.isEmpty()) {
return Futures.immediateFuture(false);
} else {
return Futures.immediateFuture(true);
return entityRelations.isEmpty() ? Futures.immediateFuture(false) : Futures.immediateFuture(true);
}
@Override
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
if (fromVersion == 0) {
var newConfigObjectNode = (ObjectNode) oldConfiguration;
if (!newConfigObjectNode.has(DIRECTION_PROPERTY_NAME)) {
throw new TbNodeException("property to update: '" + DIRECTION_PROPERTY_NAME + "' doesn't exists in configuration!");
}
String direction = newConfigObjectNode.get(DIRECTION_PROPERTY_NAME).asText();
if (EntitySearchDirection.TO.name().equals(direction)) {
newConfigObjectNode.put(DIRECTION_PROPERTY_NAME, EntitySearchDirection.FROM.name());
return new TbPair<>(true, newConfigObjectNode);
}
if (EntitySearchDirection.FROM.name().equals(direction)) {
newConfigObjectNode.put(DIRECTION_PROPERTY_NAME, EntitySearchDirection.TO.name());
return new TbPair<>(true, newConfigObjectNode);
}
throw new TbNodeException("property to update: '" + DIRECTION_PROPERTY_NAME + "' has invalid value!");
}
return new TbPair<>(false, oldConfiguration);
}
}

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeConfiguration.java

@ -17,6 +17,7 @@ package org.thingsboard.rule.engine.filter;
import lombok.Data;
import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
/**
@ -33,9 +34,9 @@ public class TbCheckRelationNodeConfiguration implements NodeConfiguration<TbChe
@Override
public TbCheckRelationNodeConfiguration defaultConfiguration() {
TbCheckRelationNodeConfiguration configuration = new TbCheckRelationNodeConfiguration();
var configuration = new TbCheckRelationNodeConfiguration();
configuration.setDirection(EntitySearchDirection.FROM.name());
configuration.setRelationType("Contains");
configuration.setRelationType(EntityRelation.CONTAINS_TYPE);
configuration.setCheckForSingleEntity(true);
return configuration;
}

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java

@ -34,7 +34,8 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
relationTypes = {"default"},
configClazz = EmptyNodeConfiguration.class,
nodeDescription = "Route incoming messages based on the name of the device profile",
nodeDetails = "Route incoming messages based on the name of the device profile. The device profile name is case-sensitive",
nodeDetails = "Route incoming messages based on the name of the device profile. The device profile name is case-sensitive<br><br>" +
"Output connections: <i>Device profile name</i> or <code>Failure</code>",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig")
public class TbDeviceTypeSwitchNode extends TbAbstractTypeSwitchNode {
@ -42,7 +43,8 @@ public class TbDeviceTypeSwitchNode extends TbAbstractTypeSwitchNode {
@Override
protected String getRelationType(TbContext ctx, EntityId originator) throws TbNodeException {
if (!EntityType.DEVICE.equals(originator.getEntityType())) {
throw new TbNodeException("Unsupported originator type: " + originator.getEntityType() + "! Only 'DEVICE' type is allowed.");
throw new TbNodeException("Unsupported originator type: " + originator.getEntityType().getNormalName() +
"! Only " + EntityType.DEVICE.getNormalName() + " type is allowed.");
}
DeviceProfile deviceProfile = ctx.getDeviceProfileCache().get(ctx.getTenantId(), (DeviceId) originator);
if (deviceProfile == null) {

9
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java

@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.script.ScriptLanguage;
@ -32,7 +33,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "script", relationTypes = {"True", "False"},
name = "script",
relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE},
configClazz = TbJsFilterNodeConfiguration.class,
nodeDescription = "Filter incoming messages using TBEL or JS script",
nodeDetails = "Evaluates boolean function using incoming message. " +
@ -40,7 +42,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"Script function should return boolean value and accepts three parameters: <br/>" +
"Message payload can be accessed via <code>msg</code> property. For example <code>msg.temperature < 10;</code><br/>" +
"Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
"Message type can be accessed via <code>msgType</code> property.",
"Message type can be accessed via <code>msgType</code> property.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeScriptConfig"
)
@ -62,7 +65,7 @@ public class TbJsFilterNode implements TbNode {
withCallback(scriptEngine.executeFilterAsync(msg),
filterResult -> {
ctx.logJsEvalResponse();
ctx.tellNext(msg, filterResult ? "True" : "False");
ctx.tellNext(msg, filterResult ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE);
},
t -> {
ctx.tellFailure(msg, t);

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

@ -44,7 +44,8 @@ import java.util.Set;
"If Array is empty - message not routed to next Node. " +
"Message payload can be accessed via <code>msg</code> property. For example <code>msg.temperature < 10;</code><br/>" +
"Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
"Message type can be accessed via <code>msgType</code> property.",
"Message type can be accessed via <code>msgType</code> property.<br><br>" +
"Output connections: <i>Custom connection(s) defined by switch node</i> or <code>Failure</code>",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeSwitchConfig")
public class TbJsSwitchNode implements TbNode {

10
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java

@ -21,6 +21,7 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@ -31,11 +32,12 @@ import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "message type",
name = "message type filter",
configClazz = TbMsgTypeFilterNodeConfiguration.class,
relationTypes = {"True", "False"},
relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE},
nodeDescription = "Filter incoming messages by Message Type",
nodeDetails = "If incoming MessageType is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
nodeDetails = "If incoming message type is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeMessageTypeConfig")
public class TbMsgTypeFilterNode implements TbNode {
@ -49,7 +51,7 @@ public class TbMsgTypeFilterNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
ctx.tellNext(msg, config.getMessageTypes().contains(msg.getType()) ? "True" : "False");
ctx.tellNext(msg, config.getMessageTypes().contains(msg.getType()) ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE);
}
}

13
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java

@ -17,11 +17,14 @@ package org.thingsboard.rule.engine.filter;
import lombok.Data;
import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import java.util.Arrays;
import java.util.List;
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST;
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST;
import static org.thingsboard.server.common.data.msg.TbMsgType.TO_SERVER_RPC_REQUEST;
/**
* Created by ashvayka on 19.01.18.
*/
@ -32,11 +35,11 @@ public class TbMsgTypeFilterNodeConfiguration implements NodeConfiguration<TbMsg
@Override
public TbMsgTypeFilterNodeConfiguration defaultConfiguration() {
TbMsgTypeFilterNodeConfiguration configuration = new TbMsgTypeFilterNodeConfiguration();
var configuration = new TbMsgTypeFilterNodeConfiguration();
configuration.setMessageTypes(Arrays.asList(
SessionMsgType.POST_ATTRIBUTES_REQUEST.name(),
SessionMsgType.POST_TELEMETRY_REQUEST.name(),
SessionMsgType.TO_SERVER_RPC_REQUEST.name()));
POST_ATTRIBUTES_REQUEST.name(),
POST_TELEMETRY_REQUEST.name(),
TO_SERVER_RPC_REQUEST.name()));
return configuration;
}
}

90
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java

@ -19,26 +19,24 @@ import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "message type switch",
configClazz = EmptyNodeConfiguration.class,
relationTypes = {"Post attributes", "Post telemetry", "RPC Request from Device", "RPC Request to Device", "RPC Queued", "RPC Sent", "RPC Delivered", "RPC Successful", "RPC Timeout", "RPC Expired", "RPC Failed", "RPC Deleted",
"Activity Event", "Inactivity Event", "Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned",
"Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Alarm Acknowledged", "Alarm Cleared", "Alarm Assigned", "Alarm Unassigned", "Comment Created", "Comment Updated", "Other", "Entity Assigned From Tenant", "Entity Assigned To Tenant",
"Relation Added or Updated", "Relation Deleted", "All Relations Deleted", "Timeseries Updated", "Timeseries Deleted"},
relationTypes = {}, // should always be empty. We add the relation types for this node in AnnotationComponentDiscoveryService.
nodeDescription = "Route incoming messages by Message Type",
nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.",
nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b>" +
" etc. via corresponding chain, otherwise <b>Other</b> chain is used.<br><br>" +
"Output connections: <i>Message type connection</i>, <code>Other</code> - if message type is custom or <code>Failure</code>",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig")
public class TbMsgTypeSwitchNode implements TbNode {
@ -52,83 +50,7 @@ public class TbMsgTypeSwitchNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
String relationType;
if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name())) {
relationType = "Post attributes";
} else if (msg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name())) {
relationType = "Post telemetry";
} else if (msg.getType().equals(SessionMsgType.TO_SERVER_RPC_REQUEST.name())) {
relationType = "RPC Request from Device";
} else if (msg.getType().equals(DataConstants.ACTIVITY_EVENT)) {
relationType = "Activity Event";
} else if (msg.getType().equals(DataConstants.INACTIVITY_EVENT)) {
relationType = "Inactivity Event";
} else if (msg.getType().equals(DataConstants.CONNECT_EVENT)) {
relationType = "Connect Event";
} else if (msg.getType().equals(DataConstants.DISCONNECT_EVENT)) {
relationType = "Disconnect Event";
} else if (msg.getType().equals(DataConstants.ENTITY_CREATED)) {
relationType = "Entity Created";
} else if (msg.getType().equals(DataConstants.ENTITY_UPDATED)) {
relationType = "Entity Updated";
} else if (msg.getType().equals(DataConstants.ENTITY_DELETED)) {
relationType = "Entity Deleted";
} else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED)) {
relationType = "Entity Assigned";
} else if (msg.getType().equals(DataConstants.ENTITY_UNASSIGNED)) {
relationType = "Entity Unassigned";
} else if (msg.getType().equals(DataConstants.ATTRIBUTES_UPDATED)) {
relationType = "Attributes Updated";
} else if (msg.getType().equals(DataConstants.ATTRIBUTES_DELETED)) {
relationType = "Attributes Deleted";
} else if (msg.getType().equals(DataConstants.ALARM_ACK)) {
relationType = "Alarm Acknowledged";
} else if (msg.getType().equals(DataConstants.ALARM_CLEAR)) {
relationType = "Alarm Cleared";
} else if (msg.getType().equals(DataConstants.ALARM_ASSIGNED)) {
relationType = "Alarm Assigned";
} else if (msg.getType().equals(DataConstants.ALARM_UNASSIGNED)) {
relationType = "Alarm Unassigned";
} else if (msg.getType().equals(DataConstants.COMMENT_CREATED)) {
relationType = "Comment Created";
} else if (msg.getType().equals(DataConstants.COMMENT_UPDATED)) {
relationType = "Comment Updated";
} else if (msg.getType().equals(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE)) {
relationType = "RPC Request to Device";
} else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED_FROM_TENANT)) {
relationType = "Entity Assigned From Tenant";
} else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED_TO_TENANT)) {
relationType = "Entity Assigned To Tenant";
} else if (msg.getType().equals(DataConstants.TIMESERIES_UPDATED)) {
relationType = "Timeseries Updated";
} else if (msg.getType().equals(DataConstants.TIMESERIES_DELETED)) {
relationType = "Timeseries Deleted";
} else if (msg.getType().equals(DataConstants.RPC_QUEUED)) {
relationType = "RPC Queued";
} else if (msg.getType().equals(DataConstants.RPC_SENT)) {
relationType = "RPC Sent";
} else if (msg.getType().equals(DataConstants.RPC_DELIVERED)) {
relationType = "RPC Delivered";
} else if (msg.getType().equals(DataConstants.RPC_SUCCESSFUL)) {
relationType = "RPC Successful";
} else if (msg.getType().equals(DataConstants.RPC_TIMEOUT)) {
relationType = "RPC Timeout";
} else if (msg.getType().equals(DataConstants.RPC_EXPIRED)) {
relationType = "RPC Expired";
} else if (msg.getType().equals(DataConstants.RPC_FAILED)) {
relationType = "RPC Failed";
} else if (msg.getType().equals(DataConstants.RPC_DELETED)) {
relationType = "RPC Deleted";
} else if (msg.getType().equals(DataConstants.RELATION_ADD_OR_UPDATE)) {
relationType = "Relation Added or Updated";
} else if (msg.getType().equals(DataConstants.RELATION_DELETED)) {
relationType = "Relation Deleted";
} else if (msg.getType().equals(DataConstants.RELATIONS_DELETED)) {
relationType = "All Relations Deleted";
} else {
relationType = "Other";
}
ctx.tellNext(msg, relationType);
ctx.tellNext(msg, TbMsgType.getRuleNodeConnectionOrElseOther(msg.getType()));
}
}

10
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java

@ -21,6 +21,7 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.plugin.ComponentType;
@ -29,11 +30,12 @@ import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "entity type",
name = "entity type filter",
configClazz = TbOriginatorTypeFilterNodeConfiguration.class,
relationTypes = {"True", "False"},
relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE},
nodeDescription = "Filter incoming messages by the type of message originator entity",
nodeDetails = "Checks that the entity type of the incoming message originator matches one of the values specified in the filter.",
nodeDetails = "Checks that the entity type of the incoming message originator matches one of the values specified in the filter.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeOriginatorTypeConfig")
public class TbOriginatorTypeFilterNode implements TbNode {
@ -48,7 +50,7 @@ public class TbOriginatorTypeFilterNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
EntityType originatorType = msg.getOriginator().getEntityType();
ctx.tellNext(msg, config.getOriginatorTypes().contains(originatorType) ? "True" : "False");
ctx.tellNext(msg, config.getOriginatorTypes().contains(originatorType) ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE);
}
}

50
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java

@ -19,8 +19,6 @@ import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType;
@ -29,55 +27,17 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
type = ComponentType.FILTER,
name = "entity type switch",
configClazz = EmptyNodeConfiguration.class,
relationTypes = {"Device", "Asset", "Alarm", "Entity View", "Tenant", "Customer", "User", "Dashboard", "Rule chain", "Rule node", "Edge"},
relationTypes = {}, // should always be empty. We add the relation types for this node in AnnotationComponentDiscoveryService.
nodeDescription = "Route incoming messages by Message Originator Type",
nodeDetails = "Routes messages to chain according to the entity type ('Device', 'Asset', etc.).",
nodeDetails = "Routes messages to chain according to the entity type ('Device', 'Asset', etc.).<br><br>" +
"Output connections: <i>Message originator type</i> or <code>Failure</code>",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig")
public class TbOriginatorTypeSwitchNode extends TbAbstractTypeSwitchNode {
@Override
protected String getRelationType(TbContext ctx, EntityId originator) throws TbNodeException {
String relationType;
EntityType originatorType = originator.getEntityType();
switch (originatorType) {
case TENANT:
relationType = "Tenant";
break;
case CUSTOMER:
relationType = "Customer";
break;
case USER:
relationType = "User";
break;
case DASHBOARD:
relationType = "Dashboard";
break;
case ASSET:
relationType = "Asset";
break;
case DEVICE:
relationType = "Device";
break;
case ENTITY_VIEW:
relationType = "Entity View";
break;
case EDGE:
relationType = "Edge";
break;
case RULE_CHAIN:
relationType = "Rule chain";
break;
case RULE_NODE:
relationType = "Rule node";
break;
case ALARM:
relationType = "Alarm";
break;
default:
throw new TbNodeException("Unsupported originator type: " + originatorType);
}
return relationType;
protected String getRelationType(TbContext ctx, EntityId originator) {
return originator.getEntityType().getNormalName();
}
}

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java

@ -21,7 +21,7 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@ -48,7 +48,7 @@ public class TbCheckpointNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
ctx.enqueueForTellNext(msg, queueName, TbRelationTypes.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error));
ctx.enqueueForTellNext(msg, queueName, TbNodeConnectionType.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error));
}
}

13
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java

@ -29,7 +29,6 @@ import com.google.pubsub.v1.PubsubMessage;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
@ -105,28 +104,28 @@ public class TbPubSubNode extends TbAbstractExternalNode {
ApiFuture<String> messageIdFuture = this.pubSubClient.publish(pubsubMessageBuilder.build());
ApiFutures.addCallback(messageIdFuture, new ApiFutureCallback<String>() {
public void onSuccess(String messageId) {
TbMsg next = processPublishResult(ctx, msg, messageId);
TbMsg next = processPublishResult(msg, messageId);
tellSuccess(ctx, next);
}
public void onFailure(Throwable t) {
TbMsg next = processException(ctx, msg, t);
TbMsg next = processException(msg, t);
tellFailure(ctx, next, t);
}
},
ctx.getExternalCallExecutor());
}
private TbMsg processPublishResult(TbContext ctx, TbMsg origMsg, String messageId) {
private TbMsg processPublishResult(TbMsg origMsg, String messageId) {
TbMsgMetaData metaData = origMsg.getMetaData().copy();
metaData.putValue(MESSAGE_ID, messageId);
return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData());
return TbMsg.transformMsgMetadata(origMsg, metaData);
}
private TbMsg processException(TbContext ctx, TbMsg origMsg, Throwable t) {
private TbMsg processException(TbMsg origMsg, Throwable t) {
TbMsgMetaData metaData = origMsg.getMetaData().copy();
metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage());
return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData());
return TbMsg.transformMsgMetadata(origMsg, metaData);
}
private Publisher initPubSubClient() throws IOException {

10
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/AbstractGeofencingNode.java

@ -48,14 +48,14 @@ public abstract class AbstractGeofencingNode<T extends TbGpsGeofencingFilterNode
abstract protected Class<T> getConfigClazz();
protected boolean checkMatches(TbMsg msg) throws TbNodeException {
JsonElement msgDataElement = new JsonParser().parse(msg.getData());
JsonElement msgDataElement = JsonParser.parseString(msg.getData());
if (!msgDataElement.isJsonObject()) {
throw new TbNodeException("Incoming Message is not a valid JSON object");
throw new TbNodeException("Incoming Message is not a valid JSON object!");
}
JsonObject msgDataObj = msgDataElement.getAsJsonObject();
double latitude = getValueFromMessageByName(msg, msgDataObj, config.getLatitudeKeyName());
double longitude = getValueFromMessageByName(msg, msgDataObj, config.getLongitudeKeyName());
List<Perimeter> perimeters = getPerimeters(msg, msgDataObj);
List<Perimeter> perimeters = getPerimeters(msg);
boolean matches = false;
for (Perimeter perimeter : perimeters) {
if (checkMatches(perimeter, latitude, longitude)) {
@ -74,11 +74,11 @@ public abstract class AbstractGeofencingNode<T extends TbGpsGeofencingFilterNode
} else if (perimeter.getPerimeterType() == PerimeterType.POLYGON) {
return GeoUtil.contains(perimeter.getPolygonsDefinition(), new Coordinates(latitude, longitude));
} else {
throw new TbNodeException("Unsupported perimeter type: " + perimeter.getPerimeterType());
throw new TbNodeException("Unsupported perimeter type: " + perimeter.getPerimeterType() + "!");
}
}
protected List<Perimeter> getPerimeters(TbMsg msg, JsonObject msgDataObj) throws TbNodeException {
protected List<Perimeter> getPerimeters(TbMsg msg) throws TbNodeException {
if (config.isFetchPerimeterInfoFromMessageMetadata()) {
if (StringUtils.isEmpty(config.getPerimeterKeyName())) {
// Old configuration before "perimeterKeyName" was introduced

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java

@ -45,8 +45,6 @@ public class GeoUtil {
private static final SpatialContext distCtx = SpatialContext.GEO;
private static final JtsSpatialContext jtsCtx;
private static final JsonParser JSON_PARSER = new JsonParser();
static {
JtsSpatialContextFactory factory = new JtsSpatialContextFactory();
factory.normWrapLongitude = true;
@ -64,7 +62,7 @@ public class GeoUtil {
throw new RuntimeException("Polygon string can't be empty or null!");
}
JsonArray polygonsJson = normalizePolygonsJson(JSON_PARSER.parse(polygonInString).getAsJsonArray());
JsonArray polygonsJson = normalizePolygonsJson(JsonParser.parseString(polygonInString).getAsJsonArray());
List<Geometry> polygons = buildPolygonsFromJson(polygonsJson);
Set<Geometry> holes = extractHolesFrom(polygons);
polygons.removeIf(holes::contains);

8
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java

@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@ -30,7 +31,7 @@ import org.thingsboard.server.common.msg.TbMsg;
type = ComponentType.FILTER,
name = "gps geofencing filter",
configClazz = TbGpsGeofencingFilterNodeConfiguration.class,
relationTypes = {"True", "False"},
relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE},
nodeDescription = "Filter incoming messages by GPS based geofencing",
nodeDetails = "Extracts latitude and longitude parameters from the incoming message and checks them according to configured perimeter. </br>" +
"Configuration:</br></br>" +
@ -57,14 +58,15 @@ import org.thingsboard.server.common.msg.TbMsg;
"</br></br>" +
"{\"latitude\": 48.198618758582384, \"longitude\": 24.65322245153503, \"radius\": 100.0, \"radiusUnit\": \"METER\" }" +
"</br></br>" +
"Available radius units: METER, KILOMETER, FOOT, MILE, NAUTICAL_MILE;",
"Available radius units: METER, KILOMETER, FOOT, MILE, NAUTICAL_MILE;<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeGpsGeofencingConfig")
public class TbGpsGeofencingFilterNode extends AbstractGeofencingNode<TbGpsGeofencingFilterNodeConfiguration> {
@Override
public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
ctx.tellNext(msg, checkMatches(msg) ? "True" : "False");
ctx.tellNext(msg, checkMatches(msg) ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE);
}
@Override

14
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java

@ -28,10 +28,8 @@ import org.apache.kafka.common.header.internals.RecordHeaders;
import org.springframework.util.ReflectionUtils;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.external.TbAbstractExternalNode;
import org.thingsboard.server.common.data.exception.ThingsboardKafkaClientError;
@ -167,24 +165,24 @@ public class TbKafkaNode extends TbAbstractExternalNode {
private void processRecord(TbContext ctx, TbMsg msg, RecordMetadata metadata, Exception e) {
if (e == null) {
tellSuccess(ctx, processResponse(ctx, msg, metadata));
tellSuccess(ctx, processResponse(msg, metadata));
} else {
tellFailure(ctx, processException(ctx, msg, e), e);
tellFailure(ctx, processException(msg, e), e);
}
}
private TbMsg processResponse(TbContext ctx, TbMsg origMsg, RecordMetadata recordMetadata) {
private TbMsg processResponse(TbMsg origMsg, RecordMetadata recordMetadata) {
TbMsgMetaData metaData = origMsg.getMetaData().copy();
metaData.putValue(OFFSET, String.valueOf(recordMetadata.offset()));
metaData.putValue(PARTITION, String.valueOf(recordMetadata.partition()));
metaData.putValue(TOPIC, recordMetadata.topic());
return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData());
return TbMsg.transformMsgMetadata(origMsg, metaData);
}
private TbMsg processException(TbContext ctx, TbMsg origMsg, Exception e) {
private TbMsg processException(TbMsg origMsg, Exception e) {
TbMsgMetaData metaData = origMsg.getMetaData().copy();
metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage());
return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData());
return TbMsg.transformMsgMetadata(origMsg, metaData);
}
}

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

@ -19,7 +19,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbEmail;
@ -28,6 +27,8 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@ -35,9 +36,6 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
import static org.thingsboard.rule.engine.mail.TbSendEmailNode.SEND_EMAIL_TYPE;
@Slf4j
@RuleNode(
type = ComponentType.TRANSFORMATION,
@ -69,7 +67,7 @@ public class TbMsgToEmailNode implements TbNode {
try {
TbEmail email = convert(msg);
TbMsg emailMsg = buildEmailMsg(ctx, msg, email);
ctx.tellNext(emailMsg, SUCCESS);
ctx.tellNext(emailMsg, TbNodeConnectionType.SUCCESS);
} catch (Exception ex) {
log.warn("Can not convert message to email " + ex.getMessage());
ctx.tellFailure(msg, ex);
@ -78,7 +76,7 @@ public class TbMsgToEmailNode implements TbNode {
private TbMsg buildEmailMsg(TbContext ctx, TbMsg msg, TbEmail email) throws JsonProcessingException {
String emailJson = JacksonUtil.toString(email);
return ctx.transformMsg(msg, SEND_EMAIL_TYPE, msg.getOriginator(), msg.getMetaData().copy(), emailJson);
return ctx.transformMsg(msg, TbMsgType.SEND_EMAIL, msg.getOriginator(), msg.getMetaData().copy(), emailJson);
}
private TbEmail convert(TbMsg msg) throws IOException {

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

@ -16,9 +16,8 @@
package org.thingsboard.rule.engine.mail;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.StringUtils;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbEmail;
@ -26,6 +25,8 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.external.TbAbstractExternalNode;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@ -50,7 +51,6 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
public class TbSendEmailNode extends TbAbstractExternalNode {
private static final String MAIL_PROP = "mail.";
static final String SEND_EMAIL_TYPE = "SEND_EMAIL";
private TbSendEmailNodeConfiguration config;
private JavaMailSenderImpl mailSender;
@ -70,7 +70,7 @@ public class TbSendEmailNode extends TbAbstractExternalNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
try {
validateType(msg.getType());
validateType(msg);
TbEmail email = getEmail(msg);
var tbMsg = ackIfNeeded(ctx, msg);
withCallback(ctx.getMailExecutor().executeAsync(() -> {
@ -100,8 +100,9 @@ public class TbSendEmailNode extends TbAbstractExternalNode {
return email;
}
private void validateType(String type) {
if (!SEND_EMAIL_TYPE.equals(type)) {
private void validateType(TbMsg msg) {
if (!msg.isTypeOf(TbMsgType.SEND_EMAIL)) {
String type = msg.getType();
log.warn("Not expected msg type [{}] for SendEmail Node", type);
throw new IllegalStateException("Not expected msg type " + type + " for SendEmail Node");
}

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java

@ -248,7 +248,7 @@ public class TbMathNode implements TbNode {
} else {
md.putValue(mathResultKey, Double.toString(toDoubleValue(mathResultDef, result)));
}
return TbMsg.transformMsg(msg, md);
return TbMsg.transformMsgMetadata(msg, md);
}
private double calculateResult(List<TbMathArgumentValue> args) {

16
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java

@ -29,9 +29,10 @@ import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import java.math.BigDecimal;
@ -45,11 +46,12 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
@Slf4j
@RuleNode(type = ComponentType.ENRICHMENT,
name = "calculate delta", relationTypes = {"Success", "Failure", "Other"},
name = "calculate delta", relationTypes = {TbNodeConnectionType.SUCCESS, TbNodeConnectionType.FAILURE, TbNodeConnectionType.OTHER},
configClazz = CalculateDeltaNodeConfiguration.class,
nodeDescription = "Calculates delta and amount of time passed between previous timeseries key reading " +
"and current value for this key from the incoming message",
nodeDetails = "Useful for metering use cases, when you need to calculate consumption based on pulse counter reading.",
nodeDetails = "Useful for metering use cases, when you need to calculate consumption based on pulse counter reading.<br><br>" +
"Output connections: <code>Success</code>, <code>Other</code> or <code>Failure</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeCalculateDeltaConfig")
public class CalculateDeltaNode implements TbNode {
@ -73,14 +75,14 @@ public class CalculateDeltaNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
if (!msg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name())) {
ctx.tellNext(msg, "Other");
if (!msg.isTypeOf(TbMsgType.POST_TELEMETRY_REQUEST)) {
ctx.tellNext(msg, TbNodeConnectionType.OTHER);
return;
}
JsonNode json = JacksonUtil.toJsonNode(msg.getData());
String inputKey = config.getInputValueKey();
if (!json.has(inputKey)) {
ctx.tellNext(msg, "Other");
ctx.tellNext(msg, TbNodeConnectionType.OTHER);
return;
}
withCallback(getLastValue(msg.getOriginator()),
@ -114,7 +116,7 @@ public class CalculateDeltaNode implements TbNode {
long period = previousData != null ? currentTs - previousData.ts : 0;
result.put(config.getPeriodValueKey(), period);
}
ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(result)));
ctx.tellSuccess(TbMsg.transformMsgData(msg, JacksonUtil.toString(result)));
},
t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor());
}

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java

@ -16,10 +16,11 @@
package org.thingsboard.rule.engine.metadata;
import lombok.Data;
import org.thingsboard.rule.engine.util.TbMsgSource;
@Data
public abstract class TbAbstractFetchToNodeConfiguration {
private FetchTo fetchTo;
private TbMsgSource fetchTo;
}

20
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.rule.engine.metadata;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@ -27,6 +28,7 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
@ -66,7 +68,7 @@ public abstract class TbAbstractGetAttributesNode<C extends TbGetAttributesNodeC
@Override
public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
var msgDataAsObjectNode = FetchTo.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null;
var msgDataAsObjectNode = TbMsgSource.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null;
withCallback(
findEntityIdAsync(ctx, msg),
entityId -> safePutAttributes(ctx, msg, msgDataAsObjectNode, entityId),
@ -75,6 +77,20 @@ public abstract class TbAbstractGetAttributesNode<C extends TbGetAttributesNodeC
protected abstract ListenableFuture<T> findEntityIdAsync(TbContext ctx, TbMsg msg);
protected TbPair<Boolean, JsonNode> upgradeRuleNodesWithOldPropertyToUseFetchTo(
JsonNode oldConfiguration,
String oldProperty,
String ifTrue,
String ifFalse
) throws TbNodeException {
var newConfigObjectNode = (ObjectNode) oldConfiguration;
if (!newConfigObjectNode.has(oldProperty)) {
newConfigObjectNode.put(FETCH_TO_PROPERTY_NAME, TbMsgSource.METADATA.name());
return new TbPair<>(true, newConfigObjectNode);
}
return upgradeConfigurationToUseFetchTo(oldProperty, ifTrue, ifFalse, newConfigObjectNode);
}
private void safePutAttributes(TbContext ctx, TbMsg msg, ObjectNode msgDataNode, T entityId) {
Set<TbPair<String, List<String>>> failuresPairSet = ConcurrentHashMap.newKeySet();
var getKvEntryPairFutures = Futures.allAsList(
@ -150,7 +166,7 @@ public abstract class TbAbstractGetAttributesNode<C extends TbGetAttributesNodeC
}
private TsKvEntry getValueWithTs(TsKvEntry tsKvEntry) {
var mapper = FetchTo.DATA.equals(fetchTo) ? JacksonUtil.OBJECT_MAPPER : JacksonUtil.ALLOW_UNQUOTED_FIELD_NAMES_MAPPER;
var mapper = TbMsgSource.DATA.equals(fetchTo) ? JacksonUtil.OBJECT_MAPPER : JacksonUtil.ALLOW_UNQUOTED_FIELD_NAMES_MAPPER;
var value = JacksonUtil.newObjectNode(mapper);
value.put(TS, tsKvEntry.getTs());
JacksonUtil.addKvEntry(value, tsKvEntry, VALUE, mapper);

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDataNode.java

@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.util.TbPair;
import org.thingsboard.server.common.msg.TbMsg;
@ -40,7 +41,7 @@ public abstract class TbAbstractGetEntityDataNode<T extends EntityId> extends Tb
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
var msgDataAsObjectNode = FetchTo.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null;
var msgDataAsObjectNode = TbMsgSource.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null;
withCallback(findEntityAsync(ctx, msg.getOriginator()),
entityId -> processDataAndTell(ctx, msg, entityId, msgDataAsObjectNode),
t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor());
@ -89,7 +90,7 @@ public abstract class TbAbstractGetEntityDataNode<T extends EntityId> extends Tb
} else {
throw new TbNodeException("property to update: '" + OLD_DATA_TO_FETCH_PROPERTY_NAME + "' has unexpected value: " + value + ". Allowed values: true or false!");
}
newConfigObjectNode.put(FETCH_TO_PROPERTY_NAME, FetchTo.METADATA.name());
newConfigObjectNode.put(FETCH_TO_PROPERTY_NAME, TbMsgSource.METADATA.name());
return new TbPair<>(true, newConfigObjectNode);
}

9
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java

@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.util.ContactBasedEntityDetails;
import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.server.common.data.ContactBased;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.msg.TbMsg;
@ -37,7 +38,7 @@ public abstract class TbAbstractGetEntityDetailsNode<C extends TbAbstractGetEnti
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
var msgDataAsObjectNode = FetchTo.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null;
var msgDataAsObjectNode = TbMsgSource.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null;
withCallback(getDetails(ctx, msg, msgDataAsObjectNode),
ctx::tellSuccess,
t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor());
@ -49,7 +50,7 @@ public abstract class TbAbstractGetEntityDetailsNode<C extends TbAbstractGetEnti
protected void checkIfDetailsListIsNotEmptyOrElseThrow(List<ContactBasedEntityDetails> detailsList) throws TbNodeException {
if (detailsList == null || detailsList.isEmpty()) {
throw new TbNodeException("No entity details selected!");
throw new TbNodeException("At least one entity detail should be selected!");
}
}
@ -114,9 +115,9 @@ public abstract class TbAbstractGetEntityDetailsNode<C extends TbAbstractGetEnti
private void setDetail(String property, String value, ObjectNode messageData, TbMsgMetaData msgMetaData) {
String fieldName = getPrefix() + property;
if (FetchTo.METADATA.equals(fetchTo)) {
if (TbMsgSource.METADATA.equals(fetchTo)) {
msgMetaData.putValue(fieldName, value);
} else if (FetchTo.DATA.equals(fetchTo)) {
} else if (TbMsgSource.DATA.equals(fetchTo)) {
messageData.put(fieldName, value);
}
}

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetMappedDataNode.java

@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.util.EntitiesFieldsAsyncLoader;
import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.msg.TbMsg;
@ -77,9 +78,9 @@ public abstract class TbAbstractGetMappedDataNode<T extends EntityId, C extends
for (var entry : targetKeysToSourceValuesMap.entrySet()) {
var targetKeyName = entry.getKey();
var sourceFieldValue = entry.getValue();
if (FetchTo.DATA.equals(fetchTo)) {
if (TbMsgSource.DATA.equals(fetchTo)) {
msgDataAsJsonNode.put(targetKeyName, sourceFieldValue);
} else if (FetchTo.METADATA.equals(fetchTo)) {
} else if (TbMsgSource.METADATA.equals(fetchTo)) {
msgMetaData.putValue(targetKeyName, sourceFieldValue);
}
}

39
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java

@ -25,6 +25,7 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.TbVersionedNode;
import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.util.TbPair;
@ -39,7 +40,7 @@ public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeC
protected final static String FETCH_TO_PROPERTY_NAME = "fetchTo";
protected C config;
protected FetchTo fetchTo;
protected TbMsgSource fetchTo;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
@ -71,9 +72,9 @@ public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeC
}
protected void enrichMessage(ObjectNode msgData, TbMsgMetaData metaData, KvEntry kvEntry, String targetKey) {
if (FetchTo.DATA.equals(fetchTo)) {
if (TbMsgSource.DATA.equals(fetchTo)) {
JacksonUtil.addKvEntry(msgData, kvEntry, targetKey);
} else if (FetchTo.METADATA.equals(fetchTo)) {
} else if (TbMsgSource.METADATA.equals(fetchTo)) {
metaData.putValue(targetKey, kvEntry.getValueAsString());
}
}
@ -83,9 +84,9 @@ public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeC
case DATA:
return TbMsg.transformMsgData(msg, JacksonUtil.toString(msgDataNode));
case METADATA:
return TbMsg.transformMsg(msg, msgMetaData);
return TbMsg.transformMsgMetadata(msg, msgMetaData);
default:
log.debug("Unexpected FetchTo value: {}. Allowed values: {}", fetchTo, FetchTo.values());
log.debug("Unexpected FetchTo value: {}. Allowed values: {}", fetchTo, TbMsgSource.values());
return msg;
}
}
@ -96,21 +97,29 @@ public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeC
String ifTrue,
String ifFalse
) throws TbNodeException {
var newConfigObjectNode = (ObjectNode) oldConfiguration;
if (!newConfigObjectNode.has(oldProperty)) {
var newConfig = (ObjectNode) oldConfiguration;
if (!newConfig.has(oldProperty)) {
throw new TbNodeException("property to update: '" + oldProperty + "' doesn't exists in configuration!");
}
var value = newConfigObjectNode.get(oldProperty).asText();
return upgradeConfigurationToUseFetchTo(oldProperty, ifTrue, ifFalse, newConfig);
}
protected TbPair<Boolean, JsonNode> upgradeConfigurationToUseFetchTo(
String oldProperty, String ifTrue,
String ifFalse, ObjectNode newConfig
) throws TbNodeException {
var value = newConfig.get(oldProperty).asText();
if ("true".equals(value)) {
newConfigObjectNode.remove(oldProperty);
newConfigObjectNode.put(FETCH_TO_PROPERTY_NAME, ifTrue);
return new TbPair<>(true, newConfigObjectNode);
newConfig.remove(oldProperty);
newConfig.put(FETCH_TO_PROPERTY_NAME, ifTrue);
return new TbPair<>(true, newConfig);
} else if ("false".equals(value)) {
newConfigObjectNode.remove(oldProperty);
newConfigObjectNode.put(FETCH_TO_PROPERTY_NAME, ifFalse);
return new TbPair<>(true, newConfigObjectNode);
newConfig.remove(oldProperty);
newConfig.put(FETCH_TO_PROPERTY_NAME, ifFalse);
return new TbPair<>(true, newConfig);
} else {
throw new TbNodeException("property to update: '" + oldProperty + "' has unexpected value: " + value + ". Allowed values: true or false!");
throw new TbNodeException("property to update: '" + oldProperty + "' has unexpected value: "
+ value + ". Allowed values: true or false!");
}
}

15
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java

@ -23,6 +23,7 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.plugin.ComponentType;
@ -41,7 +42,9 @@ import java.util.concurrent.ExecutionException;
nodeDescription = "Adds device credentials to the message or message metadata",
nodeDetails = "if message originator type is Device and device credentials was successfully fetched, " +
"rule node enriches message or message metadata with <i>credentialsType</i> and <i>credentials</i> properties. " +
"Useful when you need to fetch device credentials and use them for further message processing. For example, use device credentials to interact with external systems.",
"Useful when you need to fetch device credentials and use them for further message processing. " +
"For example, use device credentials to interact with external systems.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeFetchDeviceCredentialsConfig")
public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo<TbFetchDeviceCredentialsNodeConfiguration> {
@ -57,7 +60,7 @@ public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo<TbFe
@Override
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
var originator = msg.getOriginator();
var msgDataAsObjectNode = FetchTo.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null;
var msgDataAsObjectNode = TbMsgSource.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null;
if (!EntityType.DEVICE.equals(originator.getEntityType())) {
ctx.tellFailure(msg, new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "!"));
return;
@ -72,14 +75,14 @@ public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo<TbFe
var credentialsType = deviceCredentials.getCredentialsType();
var credentialsInfo = ctx.getDeviceCredentialsService().toCredentialsInfo(deviceCredentials);
var metaData = msg.getMetaData().copy();
if (FetchTo.METADATA.equals(fetchTo)) {
if (TbMsgSource.METADATA.equals(fetchTo)) {
metaData.putValue(CREDENTIALS_TYPE, credentialsType.name());
if (credentialsType.equals(DeviceCredentialsType.ACCESS_TOKEN) || credentialsType.equals(DeviceCredentialsType.X509_CERTIFICATE)) {
metaData.putValue(CREDENTIALS, credentialsInfo.asText());
} else {
metaData.putValue(CREDENTIALS, JacksonUtil.toString(credentialsInfo));
}
} else if (FetchTo.DATA.equals(fetchTo)) {
} else if (TbMsgSource.DATA.equals(fetchTo)) {
msgDataAsObjectNode.put(CREDENTIALS_TYPE, credentialsType.name());
msgDataAsObjectNode.set(CREDENTIALS, credentialsInfo);
}
@ -93,8 +96,8 @@ public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo<TbFe
upgradeRuleNodesWithOldPropertyToUseFetchTo(
oldConfiguration,
"fetchToMetadata",
FetchTo.METADATA.name(),
FetchTo.DATA.name()) :
TbMsgSource.METADATA.name(),
TbMsgSource.DATA.name()) :
new TbPair<>(false, oldConfiguration);
}

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java

@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.rule.engine.util.TbMsgSource;
@Data
@EqualsAndHashCode(callSuper = true)
@ -28,7 +29,7 @@ public class TbFetchDeviceCredentialsNodeConfiguration extends TbAbstractFetchTo
@Override
public TbFetchDeviceCredentialsNodeConfiguration defaultConfiguration() {
var configuration = new TbFetchDeviceCredentialsNodeConfiguration();
configuration.setFetchTo(FetchTo.METADATA);
configuration.setFetchTo(TbMsgSource.METADATA);
return configuration;
}

8
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java

@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.util.TbPair;
@ -40,7 +41,8 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDescription = "Adds attributes and/or latest timeseries data for the message originator to the message or message metadata",
nodeDetails = "Useful when you need to retrieve some attributes or the latest telemetry readings from the message originator " +
"that are not included in the incoming message to use them for further message processing. " +
"For example to filter messages based on the threshold value stored in the attributes.",
"For example to filter messages based on the threshold value stored in the attributes.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeOriginatorAttributesConfig")
public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttributesNodeConfiguration, EntityId> {
@ -61,8 +63,8 @@ public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttrib
upgradeRuleNodesWithOldPropertyToUseFetchTo(
oldConfiguration,
"fetchToData",
FetchTo.DATA.name(),
FetchTo.METADATA.name()) :
TbMsgSource.DATA.name(),
TbMsgSource.METADATA.name()) :
new TbPair<>(false, oldConfiguration);
}

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java

@ -18,6 +18,7 @@ package org.thingsboard.rule.engine.metadata;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.rule.engine.util.TbMsgSource;
import java.util.Collections;
import java.util.List;
@ -47,7 +48,7 @@ public class TbGetAttributesNodeConfiguration extends TbAbstractFetchToNodeConfi
configuration.setLatestTsKeyNames(Collections.emptyList());
configuration.setTellFailureIfAbsent(true);
configuration.setGetLatestValueWithTs(false);
configuration.setFetchTo(FetchTo.METADATA);
configuration.setFetchTo(TbMsgSource.METADATA);
return configuration;
}

7
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java

@ -39,7 +39,8 @@ import org.thingsboard.server.common.data.util.TbPair;
nodeDescription = "Adds message originator customer attributes or latest telemetry into message or message metadata",
nodeDetails = "Useful in multi-customer solutions where each customer has a different configuration or threshold set " +
"that is stored as customer attributes or telemetry data and used for dynamic message filtering, transformation, " +
"or actions such as alarm creation if the threshold is exceeded.",
"or actions such as alarm creation if the threshold is exceeded.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeCustomerAttributesConfig")
public class TbGetCustomerAttributeNode extends TbAbstractGetEntityDataNode<CustomerId> {
@ -64,9 +65,7 @@ public class TbGetCustomerAttributeNode extends TbAbstractGetEntityDataNode<Cust
@Override
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
return fromVersion == 0 ?
upgradeToUseFetchToAndDataToFetch(oldConfiguration) :
new TbPair<>(false, oldConfiguration);
return fromVersion == 0 ? upgradeToUseFetchToAndDataToFetch(oldConfiguration) : new TbPair<>(false, oldConfiguration);
}
}

8
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java

@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.HasCustomerId;
import org.thingsboard.server.common.data.HasName;
@ -47,7 +48,8 @@ import java.util.NoSuchElementException;
version = 1,
nodeDescription = "Adds message originator customer details into message or message metadata",
nodeDetails = "Useful in multi-customer solutions where we need dynamically use customer contact information " +
"such as email, phone, address, etc., for notifications via email, SMS, and other notification providers.",
"such as email, phone, address, etc., for notifications via email, SMS, and other notification providers.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeEntityDetailsConfig")
public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetCustomerDetailsNodeConfiguration, CustomerId> {
@ -111,8 +113,8 @@ public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode<TbG
upgradeRuleNodesWithOldPropertyToUseFetchTo(
oldConfiguration,
"addToMetadata",
FetchTo.METADATA.name(),
FetchTo.DATA.name()) :
TbMsgSource.METADATA.name(),
TbMsgSource.DATA.name()) :
new TbPair<>(false, oldConfiguration);
}

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeConfiguration.java

@ -18,6 +18,7 @@ package org.thingsboard.rule.engine.metadata;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.rule.engine.util.TbMsgSource;
import java.util.Collections;
@ -29,7 +30,7 @@ public class TbGetCustomerDetailsNodeConfiguration extends TbAbstractGetEntityDe
public TbGetCustomerDetailsNodeConfiguration defaultConfiguration() {
var configuration = new TbGetCustomerDetailsNodeConfiguration();
configuration.setDetailsList(Collections.emptyList());
configuration.setFetchTo(FetchTo.DATA);
configuration.setFetchTo(TbMsgSource.DATA);
return configuration;
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save