Browse Source

Refactoring notification engine

pull/2436/head
Volodymyr Babak 6 years ago
parent
commit
cd2908fb59
  1. 6
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  2. 6
      application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
  3. 32
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
  4. 4
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainManagerActor.java
  5. 2
      application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java
  6. 4
      application/src/main/java/org/thingsboard/server/controller/AlarmController.java
  7. 9
      application/src/main/java/org/thingsboard/server/controller/AssetController.java
  8. 60
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  9. 8
      application/src/main/java/org/thingsboard/server/controller/DashboardController.java
  10. 12
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  11. 7
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  12. 9
      application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
  13. 10
      application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
  14. 32
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  15. 4
      application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java
  16. 183
      application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java
  17. 18
      application/src/main/java/org/thingsboard/server/service/edge/EdgeNotificationService.java
  18. 100
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  19. 2
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  20. 35
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeEventService.java
  21. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java
  22. 3
      common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
  23. 1
      common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java
  24. 50
      common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEvent.java
  25. 2
      common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java
  26. 35
      common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeEventId.java
  27. 2
      common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainType.java
  28. 4
      common/edge-api/pom.xml
  29. 9
      common/edge-api/src/main/proto/edge.proto
  30. 8
      common/queue/src/main/proto/queue.proto
  31. 85
      dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeEventService.java
  32. 51
      dao/src/main/java/org/thingsboard/server/dao/edge/EdgeEventDao.java
  33. 2
      dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java
  34. 10
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  35. 135
      dao/src/main/java/org/thingsboard/server/dao/model/nosql/EdgeEventEntity.java
  36. 121
      dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java
  37. 27
      dao/src/main/java/org/thingsboard/server/dao/model/type/EdgeEventTypeCodec.java
  38. 6
      dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java
  39. 26
      dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java
  40. 112
      dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java
  41. 11
      dao/src/main/resources/sql/schema-entities-hsql.sql
  42. 12
      dao/src/main/resources/sql/schema-entities.sql
  43. 4
      dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java
  44. 108
      dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java
  45. 2
      dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java
  46. 12
      dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java
  47. 23
      dao/src/test/java/org/thingsboard/server/dao/service/nosql/EdgeEventServiceNoSqlTest.java
  48. 4
      dao/src/test/java/org/thingsboard/server/dao/service/nosql/EdgeServiceNoSqlTest.java
  49. 12
      dao/src/test/java/org/thingsboard/server/dao/service/sql/EdgeEventServiceSqlTest.java
  50. 4
      dao/src/test/java/org/thingsboard/server/dao/service/sql/EdgeServiceSqlTest.java
  51. 3
      dao/src/test/resources/sql/hsql/drop-all-tables.sql
  52. 2
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java
  53. 3
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
  54. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAssignToCustomerNode.java
  55. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java
  56. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java
  57. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java
  58. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java
  59. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java
  60. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java
  61. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java
  62. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbUnassignFromCustomerNode.java
  63. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java
  64. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java
  65. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java
  66. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java
  67. 41
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/PushToEdgeNodeCallback.java
  68. 97
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java
  69. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java
  70. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java
  71. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java
  72. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java
  73. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java
  74. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java
  75. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java
  76. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java
  77. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java
  78. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingActionNode.java
  79. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java
  80. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java
  81. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java
  82. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java
  83. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java
  84. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java
  85. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java
  86. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java
  87. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java
  88. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java
  89. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java
  90. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java
  91. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java
  92. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java
  93. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java
  94. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java
  95. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNode.java
  96. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java
  97. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java
  98. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java
  99. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transaction/TbSynchronizationBeginNode.java
  100. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transaction/TbSynchronizationEndNode.java

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

@ -58,6 +58,7 @@ import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.ClaimDevicesService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.event.EventService;
@ -258,6 +259,11 @@ public class ActorSystemContext {
@Getter
private EdgeService edgeService;
@Lazy
@Autowired
@Getter
private EdgeEventService edgeEventService;
@Value("${actors.session.max_concurrent_sessions_per_device:1}")
@Getter
private long maxConcurrentSessionsPerDevice;

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

@ -51,6 +51,7 @@ import org.thingsboard.server.dao.cassandra.CassandraCluster;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.nosql.CassandraStatementTask;
@ -406,6 +407,11 @@ class DefaultTbContext implements TbContext {
return mainCtx.getEdgeService();
}
@Override
public EdgeEventService getEdgeEventService() {
return mainCtx.getEdgeEventService();
}
@Override
public EventLoopGroup getSharedEventLoop() {
return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup();

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

@ -18,14 +18,11 @@ package org.thingsboard.server.actors.ruleChain;
import akka.actor.ActorContext;
import akka.actor.ActorRef;
import akka.actor.Props;
import com.google.common.util.concurrent.FutureCallback;
import com.sun.istack.Nullable;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.service.DefaultActorService;
import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
@ -102,7 +99,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
if (!started) {
RuleChain ruleChain = service.findRuleChainById(tenantId, entityId);
if (ruleChain != null) {
if (ruleChain.getType().equals(RuleChainType.SYSTEM)) {
if (ruleChain.getType().equals(RuleChainType.CORE)) {
List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId);
log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size());
// Creating and starting the actors;
@ -124,7 +121,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
public void onUpdate(ActorContext context) {
RuleChain ruleChain = service.findRuleChainById(tenantId, entityId);
if (ruleChain != null) {
if (ruleChain.getType().equals(RuleChainType.SYSTEM)) {
if (ruleChain.getType().equals(RuleChainType.CORE)) {
ruleChainName = ruleChain.getName();
List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId);
log.trace("[{}][{}] Updating rule chain with {} nodes", tenantId, entityId, ruleNodeList.size());
@ -224,7 +221,6 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
if (targetCtx != null) {
log.trace("[{}][{}] Pushing message to target rule node", entityId, targetId);
pushMsgToNode(targetCtx, msg, "");
pushUpdatesToEdges(msg);
} else {
log.trace("[{}][{}] Rule node does not exist. Probably old message", entityId, targetId);
msg.getCallback().onSuccess();
@ -354,30 +350,6 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
}
}
private void pushUpdatesToEdges(TbMsg msg) {
switch (msg.getType()) {
case DataConstants.ENTITY_CREATED:
case DataConstants.ENTITY_UPDATED:
case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
case DataConstants.ALARM_ACK:
case DataConstants.ALARM_CLEAR:
edgeService.pushEventToEdge(tenantId, msg, new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void aVoid) {
log.debug("Event saved successfully!");
}
@Override
public void onFailure(Throwable t) {
log.debug("Failure during event save", t);
}
});
}
}
@Override
protected RuleNodeException getInactiveException() {
RuleNode firstRuleNode = firstNode != null ? firstNode.getSelf() : null;

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

@ -56,7 +56,7 @@ public abstract class RuleChainManagerActor extends ContextAwareActor {
}
protected void initRuleChains() {
for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.SYSTEM, link), ContextAwareActor.ENTITY_PACK_LIMIT)) {
for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, link), ContextAwareActor.ENTITY_PACK_LIMIT)) {
RuleChainId ruleChainId = ruleChain.getId();
log.debug("[{}|{}] Creating rule chain actor", ruleChainId.getEntityType(), ruleChain.getId());
//TODO: remove this cast making UUIDBased subclass of EntityId an interface and vice versa.
@ -67,7 +67,7 @@ public abstract class RuleChainManagerActor extends ContextAwareActor {
}
protected void visit(RuleChain entity, ActorRef actorRef) {
if (entity != null && entity.isRoot() && entity.getType().equals(RuleChainType.SYSTEM)) {
if (entity != null && entity.isRoot() && entity.getType().equals(RuleChainType.CORE)) {
rootChain = entity;
rootChainActor = actorRef;
}

2
application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java

@ -206,7 +206,7 @@ public class TenantActor extends RuleChainManagerActor {
if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) {
RuleChain ruleChain = systemContext.getRuleChainService().
findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId()));
if (ruleChain != null && ruleChain.getType().equals(RuleChainType.SYSTEM)) {
if (ruleChain != null && ruleChain.getType().equals(RuleChainType.CORE)) {
visit(ruleChain, target);
}
}

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

@ -125,6 +125,8 @@ public class AlarmController extends BaseController {
alarmService.ackAlarm(getCurrentUser().getTenantId(), alarmId, ackTs).get();
alarm.setAckTs(ackTs);
logEntityAction(alarmId, alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_ACK, null);
sendNotificationMsgToEdgeService(getTenantId(), alarmId, ActionType.ALARM_ACK);
} catch (Exception e) {
throw handleException(e);
}
@ -142,6 +144,8 @@ public class AlarmController extends BaseController {
alarmService.clearAlarm(getCurrentUser().getTenantId(), alarmId, null, clearTs).get();
alarm.setClearTs(clearTs);
logEntityAction(alarmId, alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_CLEAR, null);
sendNotificationMsgToEdgeService(getTenantId(), alarmId, ActionType.ALARM_CLEAR);
} catch (Exception e) {
throw handleException(e);
}

9
application/src/main/java/org/thingsboard/server/controller/AssetController.java

@ -27,12 +27,14 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetSearchQuery;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
@ -86,6 +88,8 @@ public class AssetController extends BaseController {
Asset savedAsset = checkNotNull(assetService.saveAsset(asset));
sendNotificationMsgToEdgeService(savedAsset.getTenantId(), savedAsset.getId(), EdgeEventType.ASSET, asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
logEntityAction(savedAsset.getId(), savedAsset,
savedAsset.getCustomerId(),
asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
@ -112,6 +116,7 @@ public class AssetController extends BaseController {
asset.getCustomerId(),
ActionType.DELETED, null, strAssetId);
sendNotificationMsgToEdgeService(getTenantId(), assetId, EdgeEventType.ASSET, ActionType.DELETED);
} catch (Exception e) {
logEntityAction(emptyId(EntityType.ASSET),
null,
@ -354,6 +359,8 @@ public class AssetController extends BaseController {
savedAsset.getCustomerId(),
ActionType.ASSIGNED_TO_EDGE, null, strAssetId, strEdgeId, edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), savedAsset.getId(), EdgeEventType.ASSET, ActionType.ASSIGNED_TO_EDGE);
return savedAsset;
} catch (Exception e) {
@ -385,6 +392,8 @@ public class AssetController extends BaseController {
asset.getCustomerId(),
ActionType.UNASSIGNED_FROM_EDGE, null, strAssetId, edge.getId().toString(), edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), savedAsset.getId(), EdgeEventType.ASSET, ActionType.UNASSIGNED_FROM_EDGE);
return savedAsset;
} catch (Exception e) {

60
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.asset.Asset;
@ -66,6 +67,7 @@ import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.data.rule.RuleNode;
@ -83,6 +85,7 @@ import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.ClaimDevicesService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.exception.DataValidationException;
@ -95,10 +98,12 @@ import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.edge.EdgeNotificationService;
import org.thingsboard.server.service.queue.TbClusterService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.AccessControlService;
@ -108,6 +113,7 @@ import org.thingsboard.server.service.state.DeviceStateService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import javax.mail.MessagingException;
import javax.management.relation.Relation;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Optional;
@ -200,6 +206,12 @@ public abstract class BaseController {
@Autowired
protected EdgeService edgeService;
@Autowired
protected EdgeNotificationService edgeNotificationService;
@Autowired
protected EdgeEventService edgeEventService;
@Value("${server.log_controller_error_stack_trace}")
@Getter
private boolean logControllerErrorStackTrace;
@ -559,7 +571,6 @@ public abstract class BaseController {
}
if (e == null) {
pushEntityActionToRuleEngine(entityId, entity, user, customerId, actionType, additionalInfo);
// TODO: voba - refactor to push events to edge queue directly, instead of the rule engine flow
}
auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo);
}
@ -600,16 +611,6 @@ public abstract class BaseController {
case ALARM_CLEAR:
msgType = DataConstants.ALARM_CLEAR;
break;
case ASSIGNED_TO_EDGE:
msgType = DataConstants.ENTITY_ASSIGNED_TO_EDGE;
break;
case UNASSIGNED_FROM_EDGE:
msgType = DataConstants.ENTITY_UNASSIGNED_FROM_EDGE;
break;
case CREDENTIALS_UPDATED:
//TODO: voba - this is not efficient way to do this. Refactor on later stages
msgType = DataConstants.ENTITY_UPDATED;
break;
}
if (!StringUtils.isEmpty(msgType)) {
try {
@ -698,5 +699,42 @@ public abstract class BaseController {
return result;
}
protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityRelation relation, ActionType edgeEventAction) {
try {
sendNotificationMsgToEdgeService(tenantId, null, json.writeValueAsString(relation), EdgeEventType.RELATION, edgeEventAction);
} catch (Exception e) {
log.warn("Failed to push relation to core: {}", relation, e);
}
}
protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityId entityId, ActionType edgeEventAction) {
EdgeEventType edgeEventType = edgeEventService.getEdgeEventTypeByEntityType(entityId.getEntityType());
if (edgeEventType != null) {
sendNotificationMsgToEdgeService(tenantId, entityId, null, edgeEventType, edgeEventAction);
}
}
protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityId entityId, EdgeEventType edgeEventType, ActionType edgeEventAction) {
sendNotificationMsgToEdgeService(tenantId, entityId, null, edgeEventType, edgeEventAction);
}
private void sendNotificationMsgToEdgeService(TenantId tenantId, EntityId entityId, String entityBody, EdgeEventType edgeEventType, ActionType edgeEventAction) {
TransportProtos.EdgeNotificationMsgProto.Builder builder = TransportProtos.EdgeNotificationMsgProto.newBuilder();
builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits());
builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits());
builder.setEdgeEventType(edgeEventType.name());
builder.setEdgeEventAction(edgeEventAction.name());
if (entityId != null) {
builder.setEntityIdMSB(entityId.getId().getMostSignificantBits());
builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits());
builder.setEntityType(entityId.getEntityType().name());
}
if (entityBody != null) {
builder.setEntityBody(entityBody);
}
TransportProtos.EdgeNotificationMsgProto msg = builder.build();
tbClusterService.pushMsgToCore(tenantId, entityId != null ? entityId : tenantId,
TransportProtos.ToCoreMsg.newBuilder().setEdgeNotificationMsg(msg).build(), null);
}
}

8
application/src/main/java/org/thingsboard/server/controller/DashboardController.java

@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.ShortCustomerInfo;
import org.thingsboard.server.common.data.ShortEdgeInfo;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
@ -116,6 +117,9 @@ public class DashboardController extends BaseController {
null,
dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
sendNotificationMsgToEdgeService(savedDashboard.getTenantId(), savedDashboard.getId(),
EdgeEventType.DASHBOARD, savedDashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
return savedDashboard;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.DASHBOARD), dashboard,
@ -139,6 +143,7 @@ public class DashboardController extends BaseController {
null,
ActionType.DELETED, null, strDashboardId);
sendNotificationMsgToEdgeService(getTenantId(), dashboardId, EdgeEventType.DASHBOARD, ActionType.DELETED);
} catch (Exception e) {
logEntityAction(emptyId(EntityType.DASHBOARD),
@ -495,6 +500,7 @@ public class DashboardController extends BaseController {
null,
ActionType.ASSIGNED_TO_EDGE, null, strDashboardId, strEdgeId, edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), savedDashboard.getId(), EdgeEventType.DASHBOARD, ActionType.ASSIGNED_TO_EDGE);
return savedDashboard;
} catch (Exception e) {
@ -526,6 +532,8 @@ public class DashboardController extends BaseController {
null,
ActionType.UNASSIGNED_FROM_EDGE, null, strDashboardId, edge.getId().toString(), edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), savedDashboard.getId(), EdgeEventType.DASHBOARD, ActionType.UNASSIGNED_FROM_EDGE);
return savedDashboard;
} catch (Exception e) {

12
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.device.DeviceSearchQuery;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
@ -57,6 +58,7 @@ import org.thingsboard.server.dao.device.claim.ClaimResponse;
import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
@ -106,6 +108,8 @@ public class DeviceController extends BaseController {
tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(),
savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null);
sendNotificationMsgToEdgeService(savedDevice.getTenantId(), savedDevice.getId(), EdgeEventType.DEVICE, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
logEntityAction(savedDevice.getId(), savedDevice,
savedDevice.getCustomerId(),
device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
@ -137,6 +141,8 @@ public class DeviceController extends BaseController {
device.getCustomerId(),
ActionType.DELETED, null, strDeviceId);
sendNotificationMsgToEdgeService(getTenantId(), deviceId, EdgeEventType.DEVICE, ActionType.DELETED);
deviceStateService.onDeviceDeleted(device);
} catch (Exception e) {
logEntityAction(emptyId(EntityType.DEVICE),
@ -260,6 +266,8 @@ public class DeviceController extends BaseController {
tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId()), null);
sendNotificationMsgToEdgeService(getTenantId(), device.getId(), EdgeEventType.DEVICE, ActionType.CREDENTIALS_UPDATED);
logEntityAction(device.getId(), device,
device.getCustomerId(),
ActionType.CREDENTIALS_UPDATED, null, deviceCredentials);
@ -509,6 +517,8 @@ public class DeviceController extends BaseController {
savedDevice.getCustomerId(),
ActionType.ASSIGNED_TO_EDGE, null, strDeviceId, strEdgeId, edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), savedDevice.getId(), EdgeEventType.DEVICE, ActionType.ASSIGNED_TO_EDGE);
return savedDevice;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.DEVICE), null,
@ -538,6 +548,8 @@ public class DeviceController extends BaseController {
device.getCustomerId(),
ActionType.UNASSIGNED_FROM_EDGE, null, strDeviceId, edge.getId().toString(), edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), savedDevice.getId(), EdgeEventType.DEVICE, ActionType.UNASSIGNED_FROM_EDGE);
return savedDevice;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.DEVICE), null,

7
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -97,7 +97,7 @@ public class EdgeController extends BaseController {
if (created) {
ruleChainService.assignRuleChainToEdge(tenantId, defaultRootEdgeRuleChain.getId(), savedEdge.getId());
edgeService.setEdgeRootRuleChain(tenantId, savedEdge, defaultRootEdgeRuleChain.getId());
edgeNotificationService.setEdgeRootRuleChain(tenantId, savedEdge, defaultRootEdgeRuleChain.getId());
edgeService.assignDefaultRuleChainsToEdge(tenantId, savedEdge.getId());
}
@ -257,8 +257,7 @@ public class EdgeController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/edges", params = {"edgeName"}, method = RequestMethod.GET)
@ResponseBody
public Edge getTenantEdge(
@RequestParam String edgeName) throws ThingsboardException {
public Edge getTenantEdge(@RequestParam String edgeName) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(edgeService.findEdgeByTenantIdAndName(tenantId, edgeName));
@ -283,7 +282,7 @@ public class EdgeController extends BaseController {
accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.WRITE,
edge.getId(), edge);
Edge updatedEdge = edgeService.setEdgeRootRuleChain(getTenantId(), edge, ruleChainId);
Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(getTenantId(), edge, ruleChainId);
logEntityAction(updatedEdge.getId(), updatedEdge, null, ActionType.UPDATED, null);

9
application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java

@ -24,7 +24,9 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
@ -63,10 +65,13 @@ public class EntityRelationController extends BaseController {
relation.setTypeGroup(RelationTypeGroup.COMMON);
}
relationService.saveRelation(getTenantId(), relation);
logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(),
ActionType.RELATION_ADD_OR_UPDATE, null, relation);
logEntityAction(relation.getTo(), null, getCurrentUser().getCustomerId(),
ActionType.RELATION_ADD_OR_UPDATE, null, relation);
sendNotificationMsgToEdgeService(getTenantId(), relation, ActionType.RELATION_ADD_OR_UPDATE);
} catch (Exception e) {
logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(),
ActionType.RELATION_ADD_OR_UPDATE, e, relation);
@ -104,6 +109,8 @@ public class EntityRelationController extends BaseController {
ActionType.RELATION_DELETED, null, relation);
logEntityAction(relation.getTo(), null, getCurrentUser().getCustomerId(),
ActionType.RELATION_DELETED, null, relation);
sendNotificationMsgToEdgeService(getTenantId(), relation, ActionType.RELATION_DELETED);
} catch (Exception e) {
logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(),
ActionType.RELATION_DELETED, e, relation);
@ -125,6 +132,8 @@ public class EntityRelationController extends BaseController {
try {
relationService.deleteEntityRelations(getTenantId(), entityId);
logEntityAction(entityId, null, getCurrentUser().getCustomerId(), ActionType.RELATIONS_DELETED, null);
sendNotificationMsgToEdgeService(getTenantId(), entityId, ActionType.RELATIONS_DELETED);
} catch (Exception e) {
logEntityAction(entityId, null, getCurrentUser().getCustomerId(), ActionType.RELATIONS_DELETED, e);
throw handleException(e);

10
application/src/main/java/org/thingsboard/server/controller/EntityViewController.java

@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
@ -116,6 +117,8 @@ public class EntityViewController extends BaseController {
logEntityAction(savedEntityView.getId(), savedEntityView, null,
entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
sendNotificationMsgToEdgeService(getTenantId(), savedEntityView.getId(), EdgeEventType.ENTITY_VIEW, entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
return savedEntityView;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.ENTITY_VIEW), entityView, null,
@ -185,6 +188,8 @@ public class EntityViewController extends BaseController {
entityViewService.deleteEntityView(getTenantId(), entityViewId);
logEntityAction(entityViewId, entityView, entityView.getCustomerId(),
ActionType.DELETED, null, strEntityViewId);
sendNotificationMsgToEdgeService(getTenantId(), entityViewId, EdgeEventType.ENTITY_VIEW, ActionType.DELETED);
} catch (Exception e) {
logEntityAction(emptyId(EntityType.ENTITY_VIEW),
null,
@ -389,6 +394,9 @@ public class EntityViewController extends BaseController {
logEntityAction(entityViewId, savedEntityView,
savedEntityView.getCustomerId(),
ActionType.ASSIGNED_TO_EDGE, null, strEntityViewId, strEdgeId, edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), savedEntityView.getId(), EdgeEventType.ENTITY_VIEW, ActionType.ASSIGNED_TO_EDGE);
return savedEntityView;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.ENTITY_VIEW), null,
@ -417,6 +425,8 @@ public class EntityViewController extends BaseController {
entityView.getCustomerId(),
ActionType.UNASSIGNED_FROM_EDGE, null, strEntityViewId, edge.getId().toString(), edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), savedEntityView.getId(), EdgeEventType.ENTITY_VIEW, ActionType.UNASSIGNED_FROM_EDGE);
return savedEntityView;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.ENTITY_VIEW), null,

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

@ -41,6 +41,7 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.RuleChainId;
@ -134,7 +135,7 @@ public class RuleChainController extends BaseController {
RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain));
if (RuleChainType.SYSTEM.equals(savedRuleChain.getType())) {
if (RuleChainType.CORE.equals(savedRuleChain.getType())) {
tbClusterService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(),
created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
}
@ -143,6 +144,12 @@ public class RuleChainController extends BaseController {
null,
created ? ActionType.ADDED : ActionType.UPDATED, null);
if (RuleChainType.EDGE.equals(savedRuleChain.getType())) {
sendNotificationMsgToEdgeService(savedRuleChain.getTenantId(),
savedRuleChain.getId(), EdgeEventType.RULE_CHAIN,
savedRuleChain.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
}
return savedRuleChain;
} catch (Exception e) {
@ -209,7 +216,7 @@ public class RuleChainController extends BaseController {
RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE);
RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData));
if (RuleChainType.SYSTEM.equals(ruleChain.getType())) {
if (RuleChainType.CORE.equals(ruleChain.getType())) {
tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED);
}
@ -217,6 +224,12 @@ public class RuleChainController extends BaseController {
null,
ActionType.UPDATED, null, ruleChainMetaData);
if (RuleChainType.EDGE.equals(ruleChain.getType())) {
sendNotificationMsgToEdgeService(ruleChain.getTenantId(),
ruleChain.getId(), EdgeEventType.RULE_CHAIN,
ActionType.UPDATED);
}
return savedRuleChainMetaData;
} catch (Exception e) {
@ -243,7 +256,7 @@ public class RuleChainController extends BaseController {
RuleChainType type = RuleChainType.valueOf(typeStr);
return checkNotNull(ruleChainService.findTenantRuleChainsByType(tenantId, type, pageLink));
} else {
return checkNotNull(ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.SYSTEM, pageLink));
return checkNotNull(ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, pageLink));
}
} catch (Exception e) {
throw handleException(e);
@ -267,7 +280,7 @@ public class RuleChainController extends BaseController {
referencingRuleChainIds.remove(ruleChain.getId());
if (RuleChainType.SYSTEM.equals(ruleChain.getType())) {
if (RuleChainType.CORE.equals(ruleChain.getType())) {
referencingRuleChainIds.forEach(referencingRuleChainId ->
tbClusterService.onEntityStateChange(ruleChain.getTenantId(), referencingRuleChainId, ComponentLifecycleEvent.UPDATED));
@ -278,6 +291,12 @@ public class RuleChainController extends BaseController {
null,
ActionType.DELETED, null, strRuleChainId);
if (RuleChainType.EDGE.equals(ruleChain.getType())) {
sendNotificationMsgToEdgeService(ruleChain.getTenantId(),
ruleChain.getId(), EdgeEventType.RULE_CHAIN,
ActionType.DELETED);
}
} catch (Exception e) {
logEntityAction(emptyId(EntityType.RULE_CHAIN),
null,
@ -407,6 +426,8 @@ public class RuleChainController extends BaseController {
null,
ActionType.ASSIGNED_TO_EDGE, null, strRuleChainId, strEdgeId, edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), savedRuleChain.getId(),
EdgeEventType.RULE_CHAIN, ActionType.ASSIGNED_TO_EDGE);
return savedRuleChain;
} catch (Exception e) {
@ -438,6 +459,9 @@ public class RuleChainController extends BaseController {
null,
ActionType.UNASSIGNED_FROM_EDGE, null, strRuleChainId, edge.getId().toString(), edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), savedRuleChain.getId(),
EdgeEventType.RULE_CHAIN, ActionType.UNASSIGNED_FROM_EDGE);
return savedRuleChain;
} catch (Exception e) {

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

@ -116,7 +116,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
}
private void putComponentIntoMaps(ComponentType type, RuleNode ruleNodeAnnotation, ComponentDescriptor component) {
if (ruleChainTypeContainsArray(RuleChainType.SYSTEM, ruleNodeAnnotation.ruleChainTypes())) {
if (ruleChainTypeContainsArray(RuleChainType.CORE, ruleNodeAnnotation.ruleChainTypes())) {
systemComponentsMap.computeIfAbsent(type, k -> new ArrayList<>()).add(component);
}
if (ruleChainTypeContainsArray(RuleChainType.EDGE, ruleNodeAnnotation.ruleChainTypes())) {
@ -225,7 +225,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
@Override
public List<ComponentDescriptor> getComponents(Set<ComponentType> types, RuleChainType ruleChainType) {
if (RuleChainType.SYSTEM.equals(ruleChainType)) {
if (RuleChainType.CORE.equals(ruleChainType)) {
return getComponents(types, systemComponentsMap);
} else if (RuleChainType.EDGE.equals(ruleChainType)) {
return getComponents(types, edgeComponentsMap);

183
application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java

@ -1,3 +1,18 @@
/**
* Copyright © 2016-2020 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.service.edge;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -17,9 +32,10 @@ import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeQueueEntityType;
import org.thingsboard.server.common.data.edge.EdgeQueueEntry;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
@ -36,6 +52,7 @@ import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.event.EventService;
@ -79,7 +96,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
private RelationService relationService;
@Autowired
private EventService eventService;
private EdgeEventService edgeEventService;
private ExecutorService tsCallBackExecutor;
@ -96,8 +113,8 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
}
@Override
public TimePageData<Event> findQueueEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) {
return eventService.findEvents(tenantId, edgeId, DataConstants.EDGE_QUEUE_EVENT_TYPE, pageLink);
public TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) {
return edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink);
}
@Override
@ -105,7 +122,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
edge.setRootRuleChainId(ruleChainId);
Edge savedEdge = edgeService.saveEdge(edge);
RuleChain ruleChain = ruleChainService.findRuleChainById(tenantId, ruleChainId);
saveEventToEdgeQueue(tenantId, edge.getId(), EdgeQueueEntityType.RULE_CHAIN, DataConstants.ENTITY_UPDATED, mapper.writeValueAsString(ruleChain), new FutureCallback<Void>() {
saveEventToEdgeQueue(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, DataConstants.ENTITY_UPDATED, mapper.writeValueAsString(ruleChain), new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void aVoid) {
log.debug("Event saved successfully!");
@ -119,28 +136,28 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
return savedEdge;
}
private void saveEventToEdgeQueue(TenantId tenantId, EdgeId edgeId, EdgeQueueEntityType entityType, String type, String data, FutureCallback<Void> callback) throws IOException {
private void saveEventToEdgeQueue(TenantId tenantId, EdgeId edgeId, EdgeEventType entityType, String type, String data, FutureCallback<Void> callback) throws IOException {
log.debug("Pushing single event to edge queue. tenantId [{}], edgeId [{}], entityType [{}], type[{}], data [{}]", tenantId, edgeId, entityType, type, data);
EdgeQueueEntry queueEntry = new EdgeQueueEntry();
queueEntry.setEntityType(entityType);
queueEntry.setType(type);
queueEntry.setData(data);
// EdgeEQueueEntry queueEntry = new EdgeQueueEntry();
// queueEntry.setEntityType(entityType);
// queueEntry.setType(type);
// queueEntry.setData(data);
Event event = new Event();
event.setEntityId(edgeId);
event.setTenantId(tenantId);
event.setType(DataConstants.EDGE_QUEUE_EVENT_TYPE);
event.setBody(mapper.valueToTree(queueEntry));
ListenableFuture<Event> saveFuture = eventService.saveAsync(event);
EdgeEvent edgeEvent = new EdgeEvent();
edgeEvent.setEdgeId(edgeId);
edgeEvent.setTenantId(tenantId);
// event.setType(DataConstants.EDGE_QUEUE_EVENT_TYPE);
// event.setBody(mapper.valueToTree(queueEntry));
ListenableFuture<EdgeEvent> saveFuture = edgeEventService.saveAsync(edgeEvent);
addMainCallback(saveFuture, callback);
}
private void addMainCallback(ListenableFuture<Event> saveFuture, final FutureCallback<Void> callback) {
Futures.addCallback(saveFuture, new FutureCallback<Event>() {
private void addMainCallback(ListenableFuture<EdgeEvent> saveFuture, final FutureCallback<Void> callback) {
Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() {
@Override
public void onSuccess(@Nullable Event result) {
public void onSuccess(@Nullable EdgeEvent result) {
callback.onSuccess(null);
}
@ -153,52 +170,52 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
@Override
public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) {
if (tbMsg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name()) ||
tbMsg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ||
tbMsg.getType().equals(DataConstants.ATTRIBUTES_UPDATED) ||
tbMsg.getType().equals(DataConstants.ATTRIBUTES_DELETED)) {
processCustomTbMsg(tenantId, tbMsg, callback);
} else {
try {
switch (tbMsg.getOriginator().getEntityType()) {
case EDGE:
processEdge(tenantId, tbMsg, callback);
break;
case ASSET:
processAsset(tenantId, tbMsg, callback);
break;
case DEVICE:
processDevice(tenantId, tbMsg, callback);
break;
case DASHBOARD:
processDashboard(tenantId, tbMsg, callback);
break;
case RULE_CHAIN:
processRuleChain(tenantId, tbMsg, callback);
break;
case ENTITY_VIEW:
processEntityView(tenantId, tbMsg, callback);
break;
case ALARM:
processAlarm(tenantId, tbMsg, callback);
break;
default:
log.debug("Entity type [{}] is not designed to be pushed to edge", tbMsg.getOriginator().getEntityType());
}
} catch (IOException e) {
log.error("Can't push to edge updates, entity type [{}], data [{}]", tbMsg.getOriginator().getEntityType(), tbMsg.getData(), e);
}
}
// if (tbMsg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name()) ||
// tbMsg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ||
// tbMsg.getType().equals(DataConstants.ATTRIBUTES_UPDATED) ||
// tbMsg.getType().equals(DataConstants.ATTRIBUTES_DELETED)) {
// processCustomTbMsg(tenantId, tbMsg, callback);
// } else {
// try {
// switch (tbMsg.getOriginator().getEntityType()) {
// case EDGE:
// processEdge(tenantId, tbMsg, callback);
// break;
// case ASSET:
// processAsset(tenantId, tbMsg, callback);
// break;
// case DEVICE:
// processDevice(tenantId, tbMsg, callback);
// break;
// case DASHBOARD:
// processDashboard(tenantId, tbMsg, callback);
// break;
// case RULE_CHAIN:
// processRuleChain(tenantId, tbMsg, callback);
// break;
// case ENTITY_VIEW:
// processEntityView(tenantId, tbMsg, callback);
// break;
// case ALARM:
// processAlarm(tenantId, tbMsg, callback);
// break;
// default:
// log.debug("Entity type [{}] is not designed to be pushed to edge", tbMsg.getOriginator().getEntityType());
// }
// } catch (IOException e) {
// log.error("Can't push to edge updates, entity type [{}], data [{}]", tbMsg.getOriginator().getEntityType(), tbMsg.getData(), e);
// }
// }
}
private void processCustomTbMsg(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) {
ListenableFuture<EdgeId> edgeIdFuture = getEdgeIdByOriginatorId(tenantId, tbMsg.getOriginator());
Futures.transform(edgeIdFuture, edgeId -> {
EdgeQueueEntityType edgeQueueEntityType = getEdgeQueueTypeByEntityType(tbMsg.getOriginator().getEntityType());
if (edgeId != null && edgeQueueEntityType != null) {
EdgeEventType edgeEventType = getEdgeQueueTypeByEntityType(tbMsg.getOriginator().getEntityType());
if (edgeId != null && edgeEventType != null) {
try {
saveEventToEdgeQueue(tenantId, edgeId, edgeQueueEntityType, tbMsg.getType(), Base64.encodeBase64String(TbMsg.toByteArray(tbMsg)), callback);
saveEventToEdgeQueue(tenantId, edgeId, edgeEventType, tbMsg.getType(), Base64.encodeBase64String(TbMsg.toByteArray(tbMsg)), callback);
} catch (IOException e) {
log.error("Error while saving custom tbMsg into Edge Queue", e);
}
@ -211,13 +228,13 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.DEVICE, callback);
processAssignedEntity(tenantId, tbMsg, EdgeEventType.DEVICE, callback);
break;
case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_CREATED:
case DataConstants.ENTITY_UPDATED:
Device device = mapper.readValue(tbMsg.getData(), Device.class);
pushEventToEdge(tenantId, device.getId(), EdgeQueueEntityType.DEVICE, tbMsg, callback);
pushEventToEdge(tenantId, device.getId(), EdgeEventType.DEVICE, tbMsg, callback);
break;
default:
log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg);
@ -240,13 +257,13 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.ASSET, callback);
processAssignedEntity(tenantId, tbMsg, EdgeEventType.ASSET, callback);
break;
case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_CREATED:
case DataConstants.ENTITY_UPDATED:
Asset asset = mapper.readValue(tbMsg.getData(), Asset.class);
pushEventToEdge(tenantId, asset.getId(), EdgeQueueEntityType.ASSET, tbMsg, callback);
pushEventToEdge(tenantId, asset.getId(), EdgeEventType.ASSET, tbMsg, callback);
break;
default:
log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg);
@ -257,13 +274,13 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.ENTITY_VIEW, callback);
processAssignedEntity(tenantId, tbMsg, EdgeEventType.ENTITY_VIEW, callback);
break;
case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_CREATED:
case DataConstants.ENTITY_UPDATED:
EntityView entityView = mapper.readValue(tbMsg.getData(), EntityView.class);
pushEventToEdge(tenantId, entityView.getId(), EdgeQueueEntityType.ENTITY_VIEW, tbMsg, callback);
pushEventToEdge(tenantId, entityView.getId(), EdgeEventType.ENTITY_VIEW, tbMsg, callback);
break;
default:
log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg);
@ -278,9 +295,9 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
case DataConstants.ALARM_ACK:
case DataConstants.ALARM_CLEAR:
Alarm alarm = mapper.readValue(tbMsg.getData(), Alarm.class);
EdgeQueueEntityType edgeQueueEntityType = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType());
if (edgeQueueEntityType != null) {
pushEventToEdge(tenantId, alarm.getOriginator(), EdgeQueueEntityType.ALARM, tbMsg, callback);
EdgeEventType edgeEventType = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType());
if (edgeEventType != null) {
pushEventToEdge(tenantId, alarm.getOriginator(), EdgeEventType.ALARM, tbMsg, callback);
}
break;
default:
@ -292,7 +309,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.DASHBOARD, callback);
processAssignedEntity(tenantId, tbMsg, EdgeEventType.DASHBOARD, callback);
break;
case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_CREATED:
@ -303,7 +320,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
if (edges != null && edges.getData() != null && !edges.getData().isEmpty()) {
try {
for (Edge edge : edges.getData()) {
pushEventToEdge(tenantId, edge.getId(), EdgeQueueEntityType.DASHBOARD, tbMsg, callback);
pushEventToEdge(tenantId, edge.getId(), EdgeEventType.DASHBOARD, tbMsg, callback);
}
} catch (IOException e) {
log.error("Can't push event to edge", e);
@ -321,7 +338,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.RULE_CHAIN, callback);
processAssignedEntity(tenantId, tbMsg, EdgeEventType.RULE_CHAIN, callback);
break;
case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_CREATED:
@ -333,7 +350,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
if (edges != null && edges.getData() != null && !edges.getData().isEmpty()) {
try {
for (Edge edge : edges.getData()) {
pushEventToEdge(tenantId, edge.getId(), EdgeQueueEntityType.RULE_CHAIN, tbMsg, callback);
pushEventToEdge(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, tbMsg, callback);
}
} catch (IOException e) {
log.error("Can't push event to edge", e);
@ -349,7 +366,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
}
private void processAssignedEntity(TenantId tenantId, TbMsg tbMsg, EdgeQueueEntityType entityType, FutureCallback<Void> callback) throws IOException {
private void processAssignedEntity(TenantId tenantId, TbMsg tbMsg, EdgeEventType entityType, FutureCallback<Void> callback) throws IOException {
EdgeId edgeId;
switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
@ -364,13 +381,12 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
}
}
private void pushEventToEdge(TenantId tenantId, EntityId originatorId, EdgeQueueEntityType edgeQueueEntityType, TbMsg tbMsg, FutureCallback<Void> callback) {
private void pushEventToEdge(TenantId tenantId, EntityId originatorId, EdgeEventType edgeEventType, TbMsg tbMsg, FutureCallback<Void> callback) {
ListenableFuture<EdgeId> edgeIdFuture = getEdgeIdByOriginatorId(tenantId, originatorId);
Futures.transform(edgeIdFuture, edgeId -> {
if (edgeId != null) {
try {
pushEventToEdge(tenantId, edgeId, edgeQueueEntityType, tbMsg, callback);
pushEventToEdge(tenantId, edgeId, edgeEventType, tbMsg, callback);
} catch (Exception e) {
log.error("Failed to push event to edge, edgeId [{}], tbMsg [{}]", edgeId, tbMsg, e);
}
@ -380,7 +396,6 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
MoreExecutors.directExecutor());
}
private ListenableFuture<EdgeId> getEdgeIdByOriginatorId(TenantId tenantId, EntityId originatorId) {
List<EntityRelation> originatorEdgeRelations = relationService.findByToAndType(tenantId, originatorId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) {
@ -391,12 +406,12 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
}
private void pushEventToEdge(TenantId tenantId, EdgeId edgeId, EdgeQueueEntityType entityType, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException {
private void pushEventToEdge(TenantId tenantId, EdgeId edgeId, EdgeEventType entityType, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException {
log.debug("Pushing event(s) to edge queue. tenantId [{}], edgeId [{}], entityType [{}], tbMsg [{}]", tenantId, edgeId, entityType, tbMsg);
saveEventToEdgeQueue(tenantId, edgeId, entityType, tbMsg.getType(), tbMsg.getData(), callback);
if (entityType.equals(EdgeQueueEntityType.RULE_CHAIN)) {
if (entityType.equals(EdgeEventType.RULE_CHAIN)) {
pushRuleChainMetadataToEdge(tenantId, edgeId, tbMsg, callback);
}
}
@ -408,7 +423,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
case DataConstants.ENTITY_UPDATED:
RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(tenantId, ruleChain.getId());
saveEventToEdgeQueue(tenantId, edgeId, EdgeQueueEntityType.RULE_CHAIN_METADATA, tbMsg.getType(), mapper.writeValueAsString(ruleChainMetaData), callback);
saveEventToEdgeQueue(tenantId, edgeId, EdgeEventType.RULE_CHAIN_METADATA, tbMsg.getType(), mapper.writeValueAsString(ruleChainMetaData), callback);
break;
default:
log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg);
@ -416,14 +431,14 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
}
private EdgeQueueEntityType getEdgeQueueTypeByEntityType(EntityType entityType) {
private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) {
switch (entityType) {
case DEVICE:
return EdgeQueueEntityType.DEVICE;
return EdgeEventType.DEVICE;
case ASSET:
return EdgeQueueEntityType.ASSET;
return EdgeEventType.ASSET;
case ENTITY_VIEW:
return EdgeQueueEntityType.ENTITY_VIEW;
return EdgeEventType.ENTITY_VIEW;
default:
log.info("Unsupported entity type: [{}]", entityType);
return null;

18
application/src/main/java/org/thingsboard/server/service/edge/EdgeNotificationService.java

@ -1,7 +1,23 @@
/**
* Copyright © 2016-2020 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.service.edge;
import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
@ -14,7 +30,7 @@ import java.io.IOException;
public interface EdgeNotificationService {
TimePageData<Event> findQueueEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException;

100
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java

@ -33,14 +33,14 @@ 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.EntityView;
import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeQueueEntry;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId;
@ -63,7 +63,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.queue.TbMsgCallback;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.gen.edge.AlarmUpdateMsg;
import org.thingsboard.server.gen.edge.ConnectRequestMsg;
import org.thingsboard.server.gen.edge.ConnectResponseCode;
@ -169,36 +168,28 @@ public final class EdgeGrpcSession implements Closeable {
void processHandleMessages() throws ExecutionException, InterruptedException {
Long queueStartTs = getQueueStartTs().get();
TimePageLink pageLink = new TimePageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount(), queueStartTs, null, true);
TimePageData<Event> pageData;
TimePageData<EdgeEvent> pageData;
UUID ifOffset = null;
do {
pageData = ctx.getEdgeNotificationService().findQueueEvents(edge.getTenantId(), edge.getId(), pageLink);
pageData = ctx.getEdgeNotificationService().findEdgeEvents(edge.getTenantId(), edge.getId(), pageLink);
if (isConnected() && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] event(s) are going to be processed.", this.sessionId, pageData.getData().size());
for (Event event : pageData.getData()) {
log.trace("[{}] Processing event [{}]", this.sessionId, event);
for (EdgeEvent edgeEvent : pageData.getData()) {
log.trace("[{}] Processing edge event [{}]", this.sessionId, edgeEvent);
try {
EdgeQueueEntry entry = objectMapper.treeToValue(event.getBody(), EdgeQueueEntry.class);
UpdateMsgType msgType = getResponseMsgType(entry.getType());
switch (msgType) {
case ENTITY_DELETED_RPC_MESSAGE:
case ENTITY_UPDATED_RPC_MESSAGE:
case ENTITY_CREATED_RPC_MESSAGE:
case ALARM_ACK_RPC_MESSAGE:
case ALARM_CLEAR_RPC_MESSAGE:
processEntityCRUDMessage(entry, msgType);
break;
case RULE_CHAIN_CUSTOM_MESSAGE:
processCustomDownlinkMessage(entry);
break;
UpdateMsgType msgType = getResponseMsgType(ActionType.valueOf(edgeEvent.getEdgeEventAction()));
if (msgType == null) {
processTelemetryMessage(edgeEvent);
} else {
processEntityCRUDMessage(edgeEvent, msgType);
}
if (ENTITY_CREATED_RPC_MESSAGE.equals(msgType)) {
pushEntityAttributesToEdge(entry);
pushEntityAttributesToEdge(edgeEvent);
}
} catch (Exception e) {
log.error("Exception during processing records from queue", e);
}
ifOffset = event.getUuidId();
ifOffset = edgeEvent.getUuidId();
}
}
if (isConnected() && pageData.hasNext()) {
@ -222,10 +213,10 @@ public final class EdgeGrpcSession implements Closeable {
}
}
private void pushEntityAttributesToEdge(EdgeQueueEntry entry) throws IOException {
private void pushEntityAttributesToEdge(EdgeEvent edgeEvent) throws IOException {
EntityId entityId = null;
String entityName = null;
switch (entry.getEntityType()) {
switch (edgeEvent.getEdgeEventType()) {
case EDGE:
Edge edge = objectMapper.readValue(entry.getData(), Edge.class);
entityId = edge.getId();
@ -277,7 +268,7 @@ public final class EdgeGrpcSession implements Closeable {
, objectMapper.writeValueAsString(entityNode));
log.debug("Sending donwlink entity data msg, entityName [{}], tbMsg [{}]", finalEntityName, tbMsg);
outputStream.onNext(ResponseMsg.newBuilder()
.setDownlinkMsg(constructDownlinkEntityDataMsg(finalEntityName, finalEntityId, tbMsg))
.setDownlinkMsg(constructEntityDataProtoMsg(finalEntityName, finalEntityId, tbMsg))
.build());
} catch (Exception e) {
log.error("[{}] Failed to send attribute updates to the edge", edge.getName(), e);
@ -290,12 +281,12 @@ public final class EdgeGrpcSession implements Closeable {
}
}
private void processCustomDownlinkMessage(EdgeQueueEntry entry) throws IOException {
log.trace("Executing processCustomDownlinkMessage, entry [{}]", entry);
private void processTelemetryMessage(EdgeEvent edgeEvent) throws IOException {
log.trace("Executing processTelemetryMessage, edgeEvent [{}]", edgeEvent);
TbMsg tbMsg = TbMsg.fromBytes(Base64.decodeBase64(entry.getData()), TbMsgCallback.EMPTY);
String entityName = null;
EntityId entityId = null;
switch (entry.getEntityType()) {
switch (edgeEvent.getEdgeEventType()) {
case DEVICE:
Device device = ctx.getDeviceService().findDeviceById(edge.getTenantId(), new DeviceId(tbMsg.getOriginator().getId()));
entityName = device.getName();
@ -316,14 +307,14 @@ public final class EdgeGrpcSession implements Closeable {
if (entityName != null && entityId != null) {
log.debug("Sending downlink entity data msg, entityName [{}], tbMsg [{}]", entityName, tbMsg);
outputStream.onNext(ResponseMsg.newBuilder()
.setDownlinkMsg(constructDownlinkEntityDataMsg(entityName, entityId, tbMsg))
.setDownlinkMsg(constructEntityDataProtoMsg(entityName, entityId, tbMsg))
.build());
}
}
private void processEntityCRUDMessage(EdgeQueueEntry entry, UpdateMsgType msgType) throws java.io.IOException {
log.trace("Executing processEntityCRUDMessage, entry [{}], msgType [{}]", entry, msgType);
switch (entry.getEntityType()) {
private void processEntityCRUDMessage(EdgeEvent edgeEvent, UpdateMsgType msgType) throws java.io.IOException {
log.trace("Executing processEntityCRUDMessage, edgeEvent [{}], msgType [{}]", edgeEvent, msgType);
switch (edgeEvent.getEdgeEventType()) {
case EDGE:
Edge edge = objectMapper.readValue(entry.getData(), Edge.class);
onEdgeUpdated(msgType, edge);
@ -476,33 +467,30 @@ public final class EdgeGrpcSession implements Closeable {
.build());
}
private UpdateMsgType getResponseMsgType(String msgType) {
if (msgType.equals(SessionMsgType.POST_TELEMETRY_REQUEST.name()) ||
msgType.equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ||
msgType.equals(DataConstants.ATTRIBUTES_UPDATED) ||
msgType.equals(DataConstants.ATTRIBUTES_DELETED)) {
return UpdateMsgType.RULE_CHAIN_CUSTOM_MESSAGE;
} else {
switch (msgType) {
case DataConstants.ENTITY_UPDATED:
return UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE;
case DataConstants.ENTITY_CREATED:
case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
return ENTITY_CREATED_RPC_MESSAGE;
case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
return UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE;
case DataConstants.ALARM_ACK:
return UpdateMsgType.ALARM_ACK_RPC_MESSAGE;
case DataConstants.ALARM_CLEAR:
return UpdateMsgType.ALARM_CLEAR_RPC_MESSAGE;
default:
throw new RuntimeException("Unsupported msgType [" + msgType + "]");
}
private UpdateMsgType getResponseMsgType(ActionType actionType) {
switch (actionType) {
case ADDED:
return UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE;
case UPDATED:
case ASSIGNED_TO_EDGE:
return ENTITY_CREATED_RPC_MESSAGE;
case DELETED:
case UNASSIGNED_FROM_EDGE:
return UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE;
case ALARM_ACK:
return UpdateMsgType.ALARM_ACK_RPC_MESSAGE;
case ALARM_CLEAR:
return UpdateMsgType.ALARM_CLEAR_RPC_MESSAGE;
case ATTRIBUTES_UPDATED:
case ATTRIBUTES_DELETED:
case TIMESERIES_DELETED:
return null;
default:
throw new RuntimeException("Unsupported actionType [" + actionType + "]");
}
}
private DownlinkMsg constructDownlinkEntityDataMsg(String entityName, EntityId entityId, TbMsg tbMsg) {
private DownlinkMsg constructEntityDataProtoMsg(String entityName, EntityId entityId, TbMsg tbMsg) {
EntityDataProto entityData = EntityDataProto.newBuilder()
.setEntityName(entityName)
.setTbMsg(ByteString.copyFrom(TbMsg.toByteArray(tbMsg)))

2
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -239,7 +239,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.6.0", SCHEMA_UPDATE_SQL);
loadSql(schemaUpdateFile, conn);
try {
conn.createStatement().execute("ALTER TABLE rule_chain ADD type varchar(255) DEFAULT 'SYSTEM'"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
conn.createStatement().execute("ALTER TABLE rule_chain ADD type varchar(255) DEFAULT 'CORE'"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
} catch (Exception e) {}
log.info("Schema updated.");
}

35
common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeEventService.java

@ -0,0 +1,35 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.edge;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink;
public interface EdgeEventService {
EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType);
ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent);
TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
}

2
common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java

@ -5,7 +5,7 @@
* 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
* 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,

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

@ -65,7 +65,4 @@ public class DataConstants {
public static final String DEFAULT_SECRET_KEY = "";
public static final String SECRET_KEY_FIELD_NAME = "secretKey";
public static final String DURATION_MS_FIELD_NAME = "durationMs";
public static final String EDGE_QUEUE_EVENT_TYPE = "EDGE_QUEUE";
}

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

@ -24,6 +24,7 @@ public enum ActionType {
UPDATED(false), // log entity
ATTRIBUTES_UPDATED(false), // log attributes/values
ATTRIBUTES_DELETED(false), // log attributes
TIMESERIES_UPDATED(false), // log timeseries
TIMESERIES_DELETED(false), // log timeseries
RPC_CALL(false), // log method and params
CREDENTIALS_UPDATED(false), // log new credentials

50
common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEvent.java

@ -0,0 +1,50 @@
/**
* Copyright © 2016-2020 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.edge;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.EdgeEventId;
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 java.util.UUID;
@Data
public class EdgeEvent extends BaseData<EdgeEventId> {
private TenantId tenantId;
private EdgeId edgeId;
private String edgeEventAction;
private UUID entityId;
private EdgeEventType edgeEventType;
private transient JsonNode entityBody;
public EdgeEvent() {
super();
}
public EdgeEvent(EdgeEventId id) {
super(id);
}
public EdgeEvent(EdgeEvent event) {
super(event);
}
}

2
common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeQueueEntityType.java → common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java

@ -15,6 +15,6 @@
*/
package org.thingsboard.server.common.data.edge;
public enum EdgeQueueEntityType {
public enum EdgeEventType {
DASHBOARD, ASSET, DEVICE, ENTITY_VIEW, ALARM, RULE_CHAIN, RULE_CHAIN_METADATA, EDGE, USER, CUSTOMER, RELATION
}

35
common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeEventId.java

@ -0,0 +1,35 @@
/**
* Copyright © 2016-2020 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.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.UUID;
public class EdgeEventId extends UUIDBased {
private static final long serialVersionUID = 1L;
@JsonCreator
public EdgeEventId(@JsonProperty("id") UUID id) {
super(id);
}
public static EdgeEventId fromString(String edgeEventId) {
return new EdgeEventId(UUID.fromString(edgeEventId));
}
}

2
common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainType.java

@ -16,5 +16,5 @@
package org.thingsboard.server.common.data.rule;
public enum RuleChainType {
SYSTEM, EDGE
CORE, EDGE
}

4
common/edge-api/pom.xml

@ -40,6 +40,10 @@
<groupId>org.thingsboard.common</groupId>
<artifactId>data</artifactId>
</dependency>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>queue</artifactId>
</dependency>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>message</artifactId>

9
common/edge-api/src/main/proto/edge.proto

@ -19,6 +19,8 @@ option java_package = "org.thingsboard.server.gen.edge";
option java_multiple_files = true;
option java_outer_classname = "EdgeProtos";
import "queue.proto";
package edge;
// Interface exported by the ThingsBoard Edge Transport.
@ -94,15 +96,16 @@ enum UpdateMsgType {
ENTITY_DELETED_RPC_MESSAGE = 2;
ALARM_ACK_RPC_MESSAGE = 3;
ALARM_CLEAR_RPC_MESSAGE = 4;
RULE_CHAIN_CUSTOM_MESSAGE = 5;
DEVICE_CONFLICT_RPC_MESSAGE = 6;
DEVICE_CONFLICT_RPC_MESSAGE = 5;
}
message EntityDataProto {
string entityName = 1;
int64 entityIdMSB = 2;
int64 entityIdLSB = 3;
bytes tbMsg = 4;
transport.PostTelemetryMsg postTelemetryMsg = 4;
transport.PostAttributeMsg postAttributesMsg = 5;
// transport.ToDeviceRpcRequestMsg ???
}
message RuleChainUpdateMsg {

8
common/queue/src/main/proto/queue.proto

@ -356,6 +356,14 @@ message FromDeviceRPCResponseProto {
message EdgeNotificationMsgProto {
int64 tenantIdMSB = 1;
int64 tenantIdLSB = 2;
string edgeEventType = 3;
string edgeEventAction = 4;
int64 entityIdMSB = 5;
int64 entityIdLSB = 6;
string entityType = 7;
string entityBody = 8;
PostTelemetryMsg postTelemetryMsg = 9;
PostAttributeMsg postAttributesMsg = 10;
}
/**

85
dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeEventService.java

@ -0,0 +1,85 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.edge;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import java.util.List;
@Service
@Slf4j
public class BaseEdgeEventService implements EdgeEventService {
@Autowired
public EdgeEventDao edgeEventDao;
@Override
public EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType) {
switch (entityType) {
case DEVICE:
return EdgeEventType.DEVICE;
case ASSET:
return EdgeEventType.ASSET;
case ENTITY_VIEW:
return EdgeEventType.ENTITY_VIEW;
case DASHBOARD:
return EdgeEventType.DASHBOARD;
case USER:
return EdgeEventType.USER;
default:
log.warn("Failed to push notification to edge service. Unsupported entity type [{}]", entityType);
return null;
}
}
@Override
public ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent) {
edgeEventValidator.validate(edgeEvent, EdgeEvent::getTenantId);
return edgeEventDao.saveAsync(edgeEvent);
}
@Override
public TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) {
List<EdgeEvent> events = edgeEventDao.findEdgeEvents(tenantId.getId(), edgeId, pageLink);
return new TimePageData<>(events, pageLink);
}
private DataValidator<EdgeEvent> edgeEventValidator =
new DataValidator<EdgeEvent>() {
@Override
protected void validateDataImpl(TenantId tenantId, EdgeEvent edgeEvent) {
if (edgeEvent.getEdgeId() == null) {
throw new DataValidationException("Edge id should be specified!");
}
if (StringUtils.isEmpty(edgeEvent.getEdgeEventAction())) {
throw new DataValidationException("Edge Event action should be specified!");
}
}
};
}

51
dao/src/main/java/org/thingsboard/server/dao/edge/EdgeEventDao.java

@ -0,0 +1,51 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.edge;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.Dao;
import java.util.List;
import java.util.UUID;
/**
* The Interface EdgeEventDao.
*/
public interface EdgeEventDao extends Dao<EdgeEvent> {
/**
* Save or update edge event object async
*
* @param edgeEvent the event object
* @return saved edge event object future
*/
ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent);
/**
* Find edge events by tenantId, edgeId and pageLink.
*
* @param tenantId the tenantId
* @param edgeId the edgeId
* @param pageLink the pageLink
* @return the event list
*/
List<EdgeEvent> findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink);
}

2
dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java

@ -5,7 +5,7 @@
* 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
* 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,

10
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -372,6 +372,16 @@ public class ModelConstants {
public static final String EDGE_ROUTING_KEY_PROPERTY = "routing_key";
public static final String EDGE_SECRET_PROPERTY = "secret";
/**
* Cassandra edge queue constants.
*/
public static final String EDGE_EVENT_COLUMN_FAMILY_NAME = "edge_event";
public static final String EDGE_EVENT_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String EDGE_EVENT_EDGE_ID_PROPERTY = "edge_id";
public static final String EDGE_EVENT_TYPE_PROPERTY = "edge_event_type";
public static final String EDGE_EVENT_ACTION_PROPERTY = "edge_event_action";
public static final String EDGE_EVENT_ENTITY_ID_PROPERTY = "entity_id";
public static final String EDGE_EVENT_ENTITY_BODY_PROPERTY = "entity_body";
/**
* Cassandra attributes and timeseries constants.

135
dao/src/main/java/org/thingsboard/server/dao/model/nosql/EdgeEventEntity.java

@ -0,0 +1,135 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.nosql;
import com.datastax.driver.core.utils.UUIDs;
import com.datastax.driver.mapping.annotations.ClusteringColumn;
import com.datastax.driver.mapping.annotations.Column;
import com.datastax.driver.mapping.annotations.PartitionKey;
import com.datastax.driver.mapping.annotations.Table;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.EdgeEventId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.EventId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.model.type.EdgeEventTypeCodec;
import org.thingsboard.server.dao.model.type.EntityTypeCodec;
import org.thingsboard.server.dao.model.type.JsonCodec;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_ACTION_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_COLUMN_FAMILY_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_EDGE_ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_ENTITY_BODY_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_ENTITY_ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_TENANT_ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_TYPE_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_BODY_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_COLUMN_FAMILY_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_ENTITY_ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_ENTITY_TYPE_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_TENANT_ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_TYPE_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_UID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
@Data
@NoArgsConstructor
@Table(name = EDGE_EVENT_COLUMN_FAMILY_NAME)
public class EdgeEventEntity implements BaseEntity<EdgeEvent> {
@Column(name = ID_PROPERTY)
private UUID id;
@PartitionKey()
@Column(name = EDGE_EVENT_TENANT_ID_PROPERTY)
private UUID tenantId;
@PartitionKey(value = 1)
@Column(name = EDGE_EVENT_EDGE_ID_PROPERTY)
private UUID edgeId;
@PartitionKey(value = 2)
@Column(name = EDGE_EVENT_TYPE_PROPERTY, codec = EdgeEventTypeCodec.class)
private EdgeEventType edgeEventType;
@PartitionKey(value = 3)
@Column(name = EDGE_EVENT_ENTITY_ID_PROPERTY)
private UUID entityId;
@ClusteringColumn()
@Column(name = EDGE_EVENT_ACTION_PROPERTY)
private String edgeEventAction;
// TODO
@ClusteringColumn(value = 1)
@Column(name = EVENT_UID_PROPERTY)
private String eventUid;
@Column(name = EDGE_EVENT_ENTITY_BODY_PROPERTY, codec = JsonCodec.class)
private JsonNode entityBody;
public EdgeEventEntity(EdgeEvent edgeEvent) {
if (edgeEvent.getId() != null) {
this.id = edgeEvent.getId().getId();
}
if (edgeEvent.getTenantId() != null) {
this.tenantId = edgeEvent.getTenantId().getId();
}
if (edgeEvent.getEdgeId() != null) {
this.edgeId = edgeEvent.getEdgeId().getId();
}
// if (event.getEntityId() != null) {
// this.entityType = event.getEntityId().getEntityType();
// this.entityId = event.getEntityId().getId();
// }
// this.edgeEventType = edgeEvent.getEdgeEventType();
// this.edgeEventAction = edgeEvent.getEdgeEventAction();
// this.entityBody = edgeEvent.getEntityBody();
}
@Override
public UUID getUuid() {
return id;
}
@Override
public void setUuid(UUID id) {
this.id = id;
}
@Override
public EdgeEvent toData() {
EdgeEvent edgeEvent = new EdgeEvent(new EdgeEventId(id));
// edgeEvent.setCreatedTime(UUIDs.unixTimestamp(id));
// edgeEvent.setTenantId(new TenantId(tenantId));
// edgeEvent.setEdgeId(new EdgeId(edgeId));
// edgeEvent.setEntityId(entityId);
// event.setBody(body);
// event.setType(eventType);
// event.setUid(eventUid);
return edgeEvent;
}
}

121
dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java

@ -0,0 +1,121 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
import com.datastax.driver.core.utils.UUIDs;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.EdgeEventId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_ACTION_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_COLUMN_FAMILY_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_EDGE_ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_ENTITY_BODY_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_ENTITY_ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_TENANT_ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_TYPE_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.EPOCH_DIFF;
import static org.thingsboard.server.dao.model.ModelConstants.TS_COLUMN;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@TypeDef(name = "json", typeClass = JsonStringType.class)
@Table(name = EDGE_EVENT_COLUMN_FAMILY_NAME)
@NoArgsConstructor
public class EdgeEventEntity extends BaseSqlEntity<EdgeEvent> implements BaseEntity<EdgeEvent> {
@Column(name = EDGE_EVENT_TENANT_ID_PROPERTY)
private String tenantId;
@Column(name = EDGE_EVENT_EDGE_ID_PROPERTY)
private String edgeId;
@Column(name = EDGE_EVENT_ENTITY_ID_PROPERTY)
private String entityId;
@Enumerated(EnumType.STRING)
@Column(name = EDGE_EVENT_TYPE_PROPERTY)
private EdgeEventType edgeEventType;
@Column(name = EDGE_EVENT_ACTION_PROPERTY)
private String edgeEventAction;
@Type(type = "json")
@Column(name = EDGE_EVENT_ENTITY_BODY_PROPERTY)
private JsonNode entityBody;
@Column(name = TS_COLUMN)
private long ts;
public EdgeEventEntity(EdgeEvent edgeEvent) {
if (edgeEvent.getId() != null) {
this.setUuid(edgeEvent.getId().getId());
this.ts = getTs(edgeEvent.getId().getId());
} else {
this.ts = System.currentTimeMillis();
}
if (edgeEvent.getTenantId() != null) {
this.tenantId = toString(edgeEvent.getTenantId().getId());
}
if (edgeEvent.getEdgeId() != null) {
this.edgeId = toString(edgeEvent.getEdgeId().getId());
}
if (edgeEvent.getEntityId() != null) {
this.entityId = toString(edgeEvent.getEntityId());
}
this.edgeEventType = edgeEvent.getEdgeEventType();
this.edgeEventAction = edgeEvent.getEdgeEventAction();
this.entityBody = edgeEvent.getEntityBody();
}
@Override
public EdgeEvent toData() {
EdgeEvent edgeEvent = new EdgeEvent(new EdgeEventId(this.getUuid()));
edgeEvent.setCreatedTime(UUIDs.unixTimestamp(this.getUuid()));
edgeEvent.setTenantId(new TenantId(toUUID(tenantId)));
edgeEvent.setEdgeId(new EdgeId(toUUID(edgeId)));
if (entityId != null) {
edgeEvent.setEntityId(toUUID(entityId));
}
edgeEvent.setEdgeEventType(edgeEventType);
edgeEvent.setEdgeEventAction(edgeEventAction);
edgeEvent.setEntityBody(entityBody);
return edgeEvent;
}
private static long getTs(UUID uuid) {
return (uuid.timestamp() - EPOCH_DIFF) / 10000;
}
}

27
dao/src/main/java/org/thingsboard/server/dao/model/type/EdgeEventTypeCodec.java

@ -0,0 +1,27 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.type;
import com.datastax.driver.extras.codecs.enums.EnumNameCodec;
import org.thingsboard.server.common.data.edge.EdgeEventType;
public class EdgeEventTypeCodec extends EnumNameCodec<EdgeEventType> {
public EdgeEventTypeCodec() {
super(EdgeEventType.class);
}
}

6
dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java

@ -289,7 +289,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
@Override
public RuleChain getRootTenantRuleChain(TenantId tenantId) {
return getRootRuleChainByType(tenantId, RuleChainType.SYSTEM);
return getRootRuleChainByType(tenantId, RuleChainType.CORE);
}
private RuleChain getRootRuleChainByType(TenantId tenantId, RuleChainType type) {
@ -566,7 +566,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
throw new DataValidationException("Rule chain name should be specified!");
}
if (ruleChain.getType() == null) {
ruleChain.setType(RuleChainType.SYSTEM);
ruleChain.setType(RuleChainType.CORE);
}
if (ruleChain.getTenantId() == null || ruleChain.getTenantId().isNullUid()) {
throw new DataValidationException("Rule chain should be assigned to tenant!");
@ -575,7 +575,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
if (tenant == null) {
throw new DataValidationException("Rule chain is referencing to non-existent tenant!");
}
if (ruleChain.isRoot() && RuleChainType.SYSTEM.equals(ruleChain.getType())) {
if (ruleChain.isRoot() && RuleChainType.CORE.equals(ruleChain.getType())) {
RuleChain rootRuleChain = getRootTenantRuleChain(ruleChain.getTenantId());
if (rootRuleChain != null && !rootRuleChain.getId().equals(ruleChain.getId())) {
throw new DataValidationException("Another root rule chain is present in scope of current tenant!");

26
dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java

@ -0,0 +1,26 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.edge;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.thingsboard.server.dao.model.sql.EdgeEventEntity;
import org.thingsboard.server.dao.util.SqlDao;
@SqlDao
public interface EdgeEventRepository extends CrudRepository<EdgeEventEntity, String>, JpaSpecificationExecutor<EdgeEventEntity> {
}

112
dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java

@ -0,0 +1,112 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.edge;
import com.datastax.driver.core.utils.UUIDs;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.UUIDConverter;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.EdgeEventId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.edge.EdgeEventDao;
import org.thingsboard.server.dao.model.sql.EdgeEventEntity;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTimeDao;
import org.thingsboard.server.dao.util.SqlDao;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@Slf4j
@Component
@SqlDao
public class JpaBaseEdgeEventDao extends JpaAbstractSearchTimeDao<EdgeEventEntity, EdgeEvent> implements EdgeEventDao {
private final UUID systemTenantId = NULL_UUID;
@Autowired
private EdgeEventRepository edgeEventRepository;
@Override
protected Class<EdgeEventEntity> getEntityClass() {
return EdgeEventEntity.class;
}
@Override
protected CrudRepository<EdgeEventEntity, String> getCrudRepository() {
return edgeEventRepository;
}
@Override
public ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent) {
log.debug("Save edge event [{}] ", edgeEvent);
if (edgeEvent.getId() == null) {
edgeEvent.setId(new EdgeEventId(UUIDs.timeBased()));
}
return service.submit(() -> save(new EdgeEventEntity(edgeEvent)).orElse(null));
}
@Override
public List<EdgeEvent> findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink) {
Specification<EdgeEventEntity> timeSearchSpec = JpaAbstractSearchTimeDao.getTimeSearchPageSpec(pageLink, "id");
Specification<EdgeEventEntity> fieldsSpec = getEntityFieldsSpec(tenantId, edgeId);
Sort.Direction sortDirection = pageLink.isAscOrder() ? Sort.Direction.ASC : Sort.Direction.DESC;
Pageable pageable = PageRequest.of(0, pageLink.getLimit(), sortDirection, ID_PROPERTY);
return DaoUtil.convertDataList(edgeEventRepository.findAll(Specification.where(timeSearchSpec).and(fieldsSpec), pageable).getContent());
}
public Optional<EdgeEvent> save(EdgeEventEntity entity) {
log.debug("Save edge event [{}] ", entity);
if (entity.getTenantId() == null) {
log.trace("Save system edge event with predefined id {}", systemTenantId);
entity.setTenantId(UUIDConverter.fromTimeUUID(systemTenantId));
}
if (entity.getUuid() == null) {
entity.setUuid(UUIDs.timeBased());
}
return Optional.of(DaoUtil.getData(edgeEventRepository.save(entity)));
}
private Specification<EdgeEventEntity> getEntityFieldsSpec(UUID tenantId, EdgeId edgeId) {
return (root, criteriaQuery, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
if (tenantId != null) {
Predicate tenantIdPredicate = criteriaBuilder.equal(root.get("tenantId"), UUIDConverter.fromTimeUUID(tenantId));
predicates.add(tenantIdPredicate);
}
if (edgeId != null) {
Predicate entityIdPredicate = criteriaBuilder.equal(root.get("edgeId"), UUIDConverter.fromTimeUUID(edgeId.getId()));
predicates.add(entityIdPredicate);
}
return criteriaBuilder.and(predicates.toArray(new Predicate[]{}));
};
}
}

11
dao/src/main/resources/sql/schema-entities-hsql.sql

@ -270,3 +270,14 @@ CREATE TABLE IF NOT EXISTS edge (
CONSTRAINT edge_name_unq_key UNIQUE (tenant_id, name),
CONSTRAINT edge_routing_key_unq_key UNIQUE (routing_key)
);
CREATE TABLE IF NOT EXISTS edge_event (
id varchar(31) NOT NULL CONSTRAINT edge_event_pkey PRIMARY KEY,
edge_id varchar(31),
edge_event_type varchar(255),
entity_id varchar(31),
edge_event_action varchar(255),
entity_body varchar(10000000),
tenant_id varchar(31),
ts bigint NOT NULL
);

12
dao/src/main/resources/sql/schema-entities.sql

@ -271,6 +271,18 @@ CREATE TABLE IF NOT EXISTS edge (
CONSTRAINT edge_routing_key_unq_key UNIQUE (routing_key)
);
CREATE TABLE IF NOT EXISTS edge_event (
id varchar(31) NOT NULL CONSTRAINT edge_event_pkey PRIMARY KEY,
edge_id varchar(31),
edge_event_type varchar(255),
entity_id varchar(31),
edge_event_action varchar(255),
entity_body varchar(10000000),
tenant_id varchar(31),
ts bigint NOT NULL
);
CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint)
LANGUAGE plpgsql AS
$$

4
dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java

@ -45,6 +45,7 @@ import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.event.EventService;
@ -125,6 +126,9 @@ public abstract class AbstractServiceTest {
@Autowired
protected EdgeService edgeService;
@Autowired
protected EdgeEventService edgeEventService;
@Autowired
private ComponentDescriptorService componentDescriptorService;

108
dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java

@ -0,0 +1,108 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.service;
import com.datastax.driver.core.utils.UUIDs;
import org.junit.Assert;
import org.junit.Test;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeEventId;
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.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneOffset;
public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest {
@Test
public void saveEdgeEvent() throws Exception {
EdgeId edgeId = new EdgeId(UUIDs.timeBased());
DeviceId deviceId = new DeviceId(UUIDs.timeBased());
EdgeEvent edgeEvent = generateEdgeEvent(null, edgeId, deviceId, DataConstants.ENTITY_CREATED);
EdgeEvent saved = edgeEventService.saveAsync(edgeEvent).get();
Assert.assertEquals(saved.getTenantId(), edgeEvent.getTenantId());
Assert.assertEquals(saved.getEdgeId(), edgeEvent.getEdgeId());
Assert.assertEquals(saved.getEntityId(), edgeEvent.getEntityId());
Assert.assertEquals(saved.getEdgeEventType(), edgeEvent.getEdgeEventType());
Assert.assertEquals(saved.getEdgeEventAction(), edgeEvent.getEdgeEventAction());
Assert.assertEquals(saved.getEntityBody(), edgeEvent.getEntityBody());
}
protected EdgeEvent generateEdgeEvent(TenantId tenantId, EdgeId edgeId, EntityId entityId, String edgeEventAction) throws IOException {
if (tenantId == null) {
tenantId = new TenantId(UUIDs.timeBased());
}
EdgeEvent edgeEvent = new EdgeEvent();
edgeEvent.setTenantId(tenantId);
edgeEvent.setEdgeId(edgeId);
edgeEvent.setEntityId(entityId.getId());
edgeEvent.setEdgeEventType(EdgeEventType.DEVICE);
edgeEvent.setEdgeEventAction(edgeEventAction);
edgeEvent.setEntityBody(readFromResource("TestJsonData.json"));
return edgeEvent;
}
@Test
public void findEdgeEventsByTimeDescOrder() throws Exception {
long timeBeforeStartTime = LocalDateTime.of(2020, Month.NOVEMBER, 1, 11, 30).toEpochSecond(ZoneOffset.UTC);
long startTime = LocalDateTime.of(2020, Month.NOVEMBER, 1, 12, 0).toEpochSecond(ZoneOffset.UTC);
long eventTime = LocalDateTime.of(2020, Month.NOVEMBER, 1, 12, 30).toEpochSecond(ZoneOffset.UTC);
long endTime = LocalDateTime.of(2020, Month.NOVEMBER, 1, 13, 0).toEpochSecond(ZoneOffset.UTC);
long timeAfterEndTime = LocalDateTime.of(2020, Month.NOVEMBER, 1, 13, 30).toEpochSecond(ZoneOffset.UTC);
EdgeId edgeId = new EdgeId(UUIDs.timeBased());
DeviceId deviceId = new DeviceId(UUIDs.timeBased());
TenantId tenantId = new TenantId(UUIDs.timeBased());
saveEdgeEventWithProvidedTime(timeBeforeStartTime, edgeId, deviceId, tenantId);
EdgeEvent savedEdgeEvent = saveEdgeEventWithProvidedTime(eventTime, edgeId, deviceId, tenantId);
EdgeEvent savedEdgeEvent2 = saveEdgeEventWithProvidedTime(eventTime + 1, edgeId, deviceId, tenantId);
EdgeEvent savedEdgeEvent3 = saveEdgeEventWithProvidedTime(eventTime + 2, edgeId, deviceId, tenantId);
saveEdgeEventWithProvidedTime(timeAfterEndTime, edgeId, deviceId, tenantId);
TimePageData<EdgeEvent> edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, new TimePageLink(2, startTime, endTime, false));
Assert.assertNotNull(edgeEvents.getData());
Assert.assertTrue(edgeEvents.getData().size() == 2);
Assert.assertTrue(edgeEvents.getData().get(0).getUuidId().equals(savedEdgeEvent3.getUuidId()));
Assert.assertTrue(edgeEvents.getData().get(1).getUuidId().equals(savedEdgeEvent2.getUuidId()));
Assert.assertTrue(edgeEvents.hasNext());
Assert.assertNotNull(edgeEvents.getNextPageLink());
edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, edgeEvents.getNextPageLink());
Assert.assertNotNull(edgeEvents.getData());
Assert.assertTrue(edgeEvents.getData().size() == 1);
Assert.assertTrue(edgeEvents.getData().get(0).getUuidId().equals(savedEdgeEvent.getUuidId()));
Assert.assertFalse(edgeEvents.hasNext());
Assert.assertNull(edgeEvents.getNextPageLink());
}
private EdgeEvent saveEdgeEventWithProvidedTime(long time, EdgeId edgeId, EntityId entityId, TenantId tenantId) throws Exception {
EdgeEvent edgeEvent = generateEdgeEvent(tenantId, edgeId, entityId, DataConstants.ENTITY_CREATED);
edgeEvent.setId(new EdgeEventId(UUIDs.startOf(time)));
return edgeEventService.saveAsync(edgeEvent).get();
}
}

2
dao/src/test/java/org/thingsboard/server/dao/service/EdgeServiceImplTest.java → dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java

@ -37,7 +37,7 @@ import java.util.List;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
public abstract class EdgeServiceImplTest extends AbstractServiceTest {
public abstract class BaseEdgeServiceTest extends AbstractServiceTest {
private IdComparator<Edge> idComparator = new IdComparator<>();

12
dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java

@ -145,7 +145,7 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest {
TextPageLink pageLink = new TextPageLink(16);
TextPageData<RuleChain> pageData = null;
do {
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.SYSTEM, pageLink);
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, pageLink);
loadedRuleChains.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
@ -160,7 +160,7 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest {
ruleChainService.deleteRuleChainsByTenantId(tenantId);
pageLink = new TextPageLink(31);
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.SYSTEM, pageLink);
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertTrue(pageData.getData().isEmpty());
@ -196,7 +196,7 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest {
TextPageLink pageLink = new TextPageLink(19, name1);
TextPageData<RuleChain> pageData = null;
do {
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.SYSTEM, pageLink);
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, pageLink);
loadedRuleChainsName1.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
@ -211,7 +211,7 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest {
List<RuleChain> loadedRuleChainsName2 = new ArrayList<>();
pageLink = new TextPageLink(4, name2);
do {
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.SYSTEM, pageLink);
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, pageLink);
loadedRuleChainsName2.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
@ -228,7 +228,7 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest {
}
pageLink = new TextPageLink(4, name1);
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.SYSTEM, pageLink);
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size());
@ -237,7 +237,7 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest {
}
pageLink = new TextPageLink(4, name2);
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.SYSTEM, pageLink);
pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size());
}

23
dao/src/test/java/org/thingsboard/server/dao/service/nosql/EdgeEventServiceNoSqlTest.java

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.service.nosql;
import org.thingsboard.server.dao.service.BaseEdgeEventServiceTest;
import org.thingsboard.server.dao.service.DaoNoSqlTest;
@DaoNoSqlTest
public class EdgeEventServiceNoSqlTest extends BaseEdgeEventServiceTest {
}

4
dao/src/test/java/org/thingsboard/server/dao/service/nosql/EdgeServiceNoSqlTest.java

@ -15,9 +15,9 @@
*/
package org.thingsboard.server.dao.service.nosql;
import org.thingsboard.server.dao.service.EdgeServiceImplTest;
import org.thingsboard.server.dao.service.BaseEdgeServiceTest;
import org.thingsboard.server.dao.service.DaoNoSqlTest;
@DaoNoSqlTest
public class EdgeServiceNoSqlTest extends EdgeServiceImplTest {
public class EdgeServiceNoSqlTest extends BaseEdgeServiceTest {
}

12
common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeQueueEntry.java → dao/src/test/java/org/thingsboard/server/dao/service/sql/EdgeEventServiceSqlTest.java

@ -13,13 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.edge;
package org.thingsboard.server.dao.service.sql;
import lombok.Data;
import org.thingsboard.server.dao.service.BaseEdgeEventServiceTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
@Data
public class EdgeQueueEntry {
private String type;
private EdgeQueueEntityType entityType;
private String data;
@DaoSqlTest
public class EdgeEventServiceSqlTest extends BaseEdgeEventServiceTest {
}

4
dao/src/test/java/org/thingsboard/server/dao/service/sql/EdgeServiceSqlTest.java

@ -15,9 +15,9 @@
*/
package org.thingsboard.server.dao.service.sql;
import org.thingsboard.server.dao.service.EdgeServiceImplTest;
import org.thingsboard.server.dao.service.BaseEdgeServiceTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
@DaoSqlTest
public class EdgeServiceSqlTest extends EdgeServiceImplTest {
public class EdgeServiceSqlTest extends BaseEdgeServiceTest {
}

3
dao/src/test/resources/sql/hsql/drop-all-tables.sql

@ -20,4 +20,5 @@ DROP TABLE IF EXISTS widgets_bundle;
DROP TABLE IF EXISTS rule_node;
DROP TABLE IF EXISTS rule_chain;
DROP TABLE IF EXISTS entity_view;
DROP TABLE IF EXISTS edge;
DROP TABLE IF EXISTS edge;
DROP TABLE IF EXISTS edge_event;

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

@ -58,6 +58,6 @@ public @interface RuleNode {
boolean customRelations() default false;
RuleChainType[] ruleChainTypes() default RuleChainType.SYSTEM;
RuleChainType[] ruleChainTypes() default RuleChainType.CORE;
}

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

@ -35,6 +35,7 @@ import org.thingsboard.server.dao.cassandra.CassandraCluster;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.nosql.CassandraStatementTask;
@ -190,6 +191,8 @@ public interface TbContext {
EdgeService getEdgeService();
EdgeEventService getEdgeEventService();
ListeningExecutor getJsExecutor();
ListeningExecutor getMailExecutor();

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

@ -38,7 +38,7 @@ import org.thingsboard.server.common.msg.TbMsg;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeAssignToCustomerConfig",
icon = "add_circle",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbAssignToCustomerNode extends TbAbstractCustomerActionNode<TbAssignToCustomerNodeConfiguration> {

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

@ -46,7 +46,7 @@ import org.thingsboard.server.common.msg.TbMsg;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeClearAlarmConfig",
icon = "notifications_off",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfiguration> {

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

@ -58,7 +58,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig",
icon = "content_copy",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbCopyAttributesToEntityViewNode implements TbNode {

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

@ -52,7 +52,7 @@ import java.util.List;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeCreateAlarmConfig",
icon = "notifications_active",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConfiguration> {

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

@ -55,7 +55,7 @@ import java.util.List;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeCreateRelationConfig",
icon = "add_circle",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateRelationNodeConfiguration> {

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

@ -45,7 +45,7 @@ import java.util.List;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeDeleteRelationConfig",
icon = "remove_circle",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> {

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

@ -38,7 +38,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeLogConfig",
icon = "menu",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbLogNode implements TbNode {

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

@ -44,7 +44,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
icon = "functions",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeMsgCountConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbMsgCountNode implements TbNode {

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

@ -35,7 +35,7 @@ import org.thingsboard.server.common.msg.TbMsg;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeUnAssignToCustomerConfig",
icon = "remove_circle",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbUnassignFromCustomerNode extends TbAbstractCustomerActionNode<TbUnassignFromCustomerNodeConfiguration> {

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

@ -47,7 +47,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeSnsConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbSnsNode implements TbNode {

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

@ -52,7 +52,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeSqsConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbSqsNode implements TbNode {

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

@ -45,7 +45,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeGeneratorConfig",
icon = "repeat",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbMsgGeneratorNode implements TbNode {

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

@ -46,7 +46,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
icon = "pause",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeMsgDelayConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbMsgDelayNode implements TbNode {

41
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/PushToEdgeNodeCallback.java

@ -1,41 +0,0 @@
/**
* Copyright © 2016-2020 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.rule.engine.edge;
import com.google.common.util.concurrent.FutureCallback;
import lombok.Data;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.server.common.msg.TbMsg;
import javax.annotation.Nullable;
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
@Data
class PushToEdgeNodeCallback implements FutureCallback<Void> {
private final TbContext ctx;
private final TbMsg msg;
@Override
public void onSuccess(@Nullable Void result) {
ctx.tellNext(msg, SUCCESS);
}
@Override
public void onFailure(Throwable t) {
ctx.tellFailure(msg, t);
}
}

97
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java

@ -15,6 +15,10 @@
*/
package org.thingsboard.rule.engine.edge;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
@ -23,10 +27,25 @@ 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.EntityType;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
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.plugin.ComponentType;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import javax.annotation.Nullable;
import java.util.List;
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
@ -40,13 +59,10 @@ import org.thingsboard.server.common.msg.session.SessionMsgType;
)
public class TbMsgPushToEdgeNode implements TbNode {
private static final String CLOUD_MSG_SOURCE = "cloud";
private static final String EDGE_MSG_SOURCE = "edge";
private static final String MSG_SOURCE_KEY = "source";
private static final String TS_METADATA_KEY = "ts";
private EmptyNodeConfiguration config;
private static final ObjectMapper json = new ObjectMapper();
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class);
@ -54,14 +70,71 @@ public class TbMsgPushToEdgeNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
if (EDGE_MSG_SOURCE.equalsIgnoreCase(msg.getMetaData().getValue(MSG_SOURCE_KEY))) {
return;
}
if (msg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name())) {
msg.getMetaData().putValue(TS_METADATA_KEY, Long.toString(System.currentTimeMillis()));
if (EntityType.DEVICE.equals(msg.getOriginator().getEntityType()) ||
EntityType.DEVICE.equals(msg.getOriginator().getEntityType()) ||
EntityType.DEVICE.equals(msg.getOriginator().getEntityType()) ||
EntityType.DEVICE.equals(msg.getOriginator().getEntityType())) {
if (SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msg.getType()) ||
SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType()) ||
DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType()) ||
DataConstants.ATTRIBUTES_DELETED.equals(msg.getType())) {
ListenableFuture<EdgeId> getEdgeIdFuture = getEdgeIdByOriginatorId(ctx, ctx.getTenantId(), msg.getOriginator());
Futures.transform(getEdgeIdFuture, edgeId -> {
EdgeEventType edgeEventTypeByEntityType = ctx.getEdgeEventService().getEdgeEventTypeByEntityType(msg.getOriginator().getEntityType());
if (edgeEventTypeByEntityType == null) {
log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType());
ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '"+ msg.getOriginator().getEntityType() + "'"));
}
ActionType actionType;
if (SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msg.getType())) {
actionType = ActionType.TIMESERIES_UPDATED;
} else if (SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType()) ||
DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType())) {
actionType = ActionType.ATTRIBUTES_UPDATED;
} else {
actionType = ActionType.ATTRIBUTES_DELETED;
}
EdgeEvent edgeEvent = new EdgeEvent();
edgeEvent.setTenantId(ctx.getTenantId());
edgeEvent.setEdgeId(edgeId);
edgeEvent.setEdgeEventAction(actionType.name());
edgeEvent.setEntityId(msg.getOriginator().getId());
edgeEvent.setEdgeEventType(edgeEventTypeByEntityType);
edgeEvent.setEntityBody(json.valueToTree(msg.getData()));
ListenableFuture<EdgeEvent> saveFuture = ctx.getEdgeEventService().saveAsync(edgeEvent);
Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() {
@Override
public void onSuccess(@Nullable EdgeEvent event) {
ctx.tellNext(msg, SUCCESS);
}
@Override
public void onFailure(Throwable th) {
log.error("Could not save edge event", th);
ctx.tellFailure(msg, th);
}
}, ctx.getDbCallbackExecutor());
return null;
}, ctx.getDbCallbackExecutor());
} else {
log.debug("Unsupported msg type {}", msg.getType());
ctx.tellFailure(msg, new RuntimeException("Unsupported msg type '" + msg.getType() + "'"));
}
} else {
log.debug("Unsupported originator type {}", msg.getOriginator().getEntityType());
ctx.tellFailure(msg, new RuntimeException("Unsupported originator type '" + msg.getOriginator().getEntityType() + "'"));
}
msg.getMetaData().putValue(MSG_SOURCE_KEY, CLOUD_MSG_SOURCE);
ctx.getEdgeService().pushEventToEdge(ctx.getTenantId(), msg, new PushToEdgeNodeCallback(ctx, msg));
}
private ListenableFuture<EdgeId> getEdgeIdByOriginatorId(TbContext ctx, TenantId tenantId, EntityId originatorId) {
ListenableFuture<List<EntityRelation>> future = ctx.getRelationService().findByToAndTypeAsync(tenantId, originatorId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
return Futures.transform(future, relations -> {
if (relations != null && relations.size() > 0) {
return new EdgeId(relations.get(0).getFrom().getId());
} else {
return null;
}
}, ctx.getDbCallbackExecutor());
}
@Override

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

@ -41,7 +41,7 @@ import java.util.Map;
"Else if the checkbox is not selected, and at least one of the keys from data or metadata of the message exists - send Message via <b>True</b> chain, otherwise, <b>False</b> chain is used. ",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeCheckMessageConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbCheckMessageNode implements TbNode {

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

@ -53,7 +53,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
nodeDetails = "If at least one relation exists - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeCheckRelationConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbCheckRelationNode implements TbNode {

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

@ -38,7 +38,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"Message type can be accessed via <code>msgType</code> property.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeScriptConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbJsFilterNode implements TbNode {

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

@ -41,7 +41,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"Message type can be accessed via <code>msgType</code> property.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeSwitchConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbJsSwitchNode implements TbNode {

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

@ -35,7 +35,7 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDetails = "If incoming MessageType is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbFilterNodeMessageTypeConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbMsgTypeFilterNode implements TbNode {

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

@ -36,7 +36,7 @@ import org.thingsboard.server.common.msg.session.SessionMsgType;
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.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbMsgTypeSwitchNode implements TbNode {

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

@ -33,7 +33,7 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDetails = "If Originator Type of incoming message is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbFilterNodeOriginatorTypeConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbOriginatorTypeFilterNode implements TbNode {

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

@ -33,7 +33,7 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDetails = "Routes messages to chain according to the originator type ('Device', 'Asset', etc.).",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbOriginatorTypeSwitchNode implements TbNode {

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

@ -51,7 +51,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodePubSubConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo=",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbPubSubNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingActionNode.java

@ -53,7 +53,7 @@ import java.util.concurrent.TimeoutException;
nodeDetails = "Extracts latitude and longitude parameters from incoming message and returns different events based on configuration parameters",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeGpsGeofencingConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbGpsGeofencingActionNode extends AbstractGeofencingNode<TbGpsGeofencingActionNodeConfiguration> {

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

@ -54,7 +54,7 @@ import java.util.List;
nodeDetails = "Extracts latitude and longitude parameters from incoming message and returns 'True' if they are inside configured perimeters, 'False' otherwise.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeGpsGeofencingConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbGpsGeofencingFilterNode extends AbstractGeofencingNode<TbGpsGeofencingFilterNodeConfiguration> {

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

@ -53,7 +53,7 @@ import java.util.Properties;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeKafkaConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg==",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbKafkaNode implements TbNode {

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

@ -42,7 +42,7 @@ import static org.thingsboard.rule.engine.mail.TbSendEmailNode.SEND_EMAIL_TYPE;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbTransformationNodeToEmailConfig",
icon = "email",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbMsgToEmailNode implements TbNode {

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

@ -48,7 +48,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeSendEmailConfig",
icon = "send",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbSendEmailNode implements TbNode {

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

@ -42,7 +42,7 @@ import org.thingsboard.server.common.msg.TbMsg;
"<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeOriginatorAttributesConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttributesNodeConfiguration, EntityId> {

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

@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
"<code>metadata.temperature</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbEnrichmentNodeCustomerAttributesConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode<CustomerId> {

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

@ -44,7 +44,7 @@ import org.thingsboard.server.common.msg.TbMsg;
"If the originator of the message is not assigned to Customer, or originator type is not supported - Message will be forwarded to <b>Failure</b> chain, otherwise, <b>Success</b> chain will be used.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeEntityDetailsConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetCustomerDetailsNodeConfiguration> {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java

@ -40,7 +40,7 @@ import org.thingsboard.server.common.msg.TbMsg;
"<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeDeviceAttributesConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode<TbGetDeviceAttrNodeConfiguration, DeviceId> {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java

@ -45,7 +45,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
nodeDetails = "Will fetch fields values specified in mapping. If specified field is not part of originator fields it will be ignored.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeOriginatorFieldsConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbGetOriginatorFieldsNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java

@ -37,7 +37,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
"<code>metadata.temperature</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbEnrichmentNodeRelatedAttributesConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java

@ -68,7 +68,7 @@ import static org.thingsboard.server.common.data.kv.Aggregation.NONE;
"<b>Note</b>: The maximum size of the fetched array is 1000 records.\n ",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbGetTelemetryNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java

@ -37,7 +37,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
"<code>metadata.temperature</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbEnrichmentNodeTenantAttributesConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbGetTenantAttributeNode extends TbEntityGetAttrNode<TenantId> {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java

@ -39,7 +39,7 @@ import org.thingsboard.server.common.msg.TbMsg;
"If the originator of the message is not assigned to Tenant, or originator type is not supported - Message will be forwarded to <b>Failure</b> chain, otherwise, <b>Success</b> chain will be used.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeEntityDetailsConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetTenantDetailsNodeConfiguration> {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java

@ -51,7 +51,7 @@ import java.util.concurrent.TimeoutException;
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeMqttConfig",
icon = "call_split",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbMqttNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java

@ -41,7 +41,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRabbitMqConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4=",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbRabbitMqNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java

@ -41,7 +41,7 @@ import org.thingsboard.server.common.msg.TbMsg;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRestApiCallConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbRestApiCallNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNode.java

@ -41,7 +41,7 @@ import java.util.UUID;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRpcReplyConfig",
icon = "call_merge",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbSendRPCReplyNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java

@ -52,7 +52,7 @@ import java.util.concurrent.TimeUnit;
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRpcRequestConfig",
icon = "call_made",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbSendRPCRequestNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java

@ -46,7 +46,7 @@ import java.util.Set;
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeAttributesConfig",
icon = "file_upload",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbMsgAttributesNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java

@ -47,7 +47,7 @@ import java.util.Map;
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeTimeseriesConfig",
icon = "file_upload",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbMsgTimeseriesNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transaction/TbSynchronizationBeginNode.java

@ -40,7 +40,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
"Size of the queue per originator and timeout values are configurable on a system level",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
@Deprecated
public class TbSynchronizationBeginNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transaction/TbSynchronizationEndNode.java

@ -40,7 +40,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
nodeDetails = "",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = ("tbNodeEmptyConfig"),
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
@Deprecated
public class TbSynchronizationEndNode implements TbNode {

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

Loading…
Cancel
Save