Browse Source

Merge pull request #11924 from AndriiLandiak/feature/edge-kafka-events

Use Kafka to store and process Edge Events to improve processing throughput
pull/12157/head
Viacheslav Klimov 2 years ago
committed by GitHub
parent
commit
9cd92e22c6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 137
      application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
  2. 7
      application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java
  3. 81
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java
  4. 764
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  5. 55
      application/src/main/java/org/thingsboard/server/service/edge/rpc/KafkaEdgeEventService.java
  6. 146
      application/src/main/java/org/thingsboard/server/service/edge/rpc/KafkaEdgeGrpcSession.java
  7. 46
      application/src/main/java/org/thingsboard/server/service/edge/rpc/PostgresEdgeGrpcSession.java
  8. 340
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java
  9. 42
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessor.java
  10. 6
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessorV1.java
  11. 82
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java
  12. 36
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java
  13. 3
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProcessor.java
  14. 11
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProcessor.java
  15. 36
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/profile/AssetProfileEdgeProcessor.java
  16. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/profile/AssetProfileProcessor.java
  17. 12
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/profile/BaseAssetProfileProcessor.java
  18. 23
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/customer/CustomerEdgeProcessor.java
  19. 14
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java
  20. 34
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java
  21. 1
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessorV2.java
  22. 19
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java
  23. 37
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java
  24. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProcessor.java
  25. 12
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/profile/BaseDeviceProfileProcessor.java
  26. 17
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/profile/DeviceProfileEdgeProcessor.java
  27. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/profile/DeviceProfileProcessor.java
  28. 22
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/edge/EdgeProcessor.java
  29. 11
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/BaseEntityViewProcessor.java
  30. 31
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java
  31. 17
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/notification/NotificationEdgeProcessor.java
  32. 29
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/oauth2/OAuth2EdgeProcessor.java
  33. 21
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/ota/OtaPackageEdgeProcessor.java
  34. 21
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/queue/QueueEdgeProcessor.java
  35. 7
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java
  36. 9
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/RelationEdgeProcessor.java
  37. 11
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/BaseResourceProcessor.java
  38. 21
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessor.java
  39. 23
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/rule/RuleChainEdgeProcessor.java
  40. 5
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/settings/AdminSettingsEdgeProcessor.java
  41. 45
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java
  42. 23
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/tenant/TenantEdgeProcessor.java
  43. 17
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/tenant/TenantProfileEdgeProcessor.java
  44. 38
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/user/UserEdgeProcessor.java
  45. 23
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetBundleEdgeProcessor.java
  46. 21
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetTypeEdgeProcessor.java
  47. 6
      application/src/main/java/org/thingsboard/server/service/entitiy/EntityStateSourcingListener.java
  48. 2
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbEdgeConsumerService.java
  49. 3
      application/src/main/java/org/thingsboard/server/service/ttl/AbstractCleanUpService.java
  50. 3
      application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java
  51. 160
      application/src/main/java/org/thingsboard/server/service/ttl/KafkaEdgeTopicsCleanUpService.java
  52. 7
      application/src/main/resources/thingsboard.yml
  53. 2
      application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java
  54. 2
      application/src/test/resources/logback-test.xml
  55. 5
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeEventService.java
  56. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java
  57. 1
      common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
  58. 3
      common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEvent.java
  59. 2
      common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java
  60. 1
      common/edge-api/src/main/proto/edge.proto
  61. 3
      common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeEventUpdateMsg.java
  62. 5
      common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeHighPriorityMsg.java
  63. 4
      common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeSessionMsg.java
  64. 2
      common/message/src/main/java/org/thingsboard/server/common/msg/edge/FromEdgeSyncResponse.java
  65. 2
      common/message/src/main/java/org/thingsboard/server/common/msg/edge/ToEdgeSyncRequest.java
  66. 44
      common/proto/src/main/java/org/thingsboard/server/common/util/ProtoUtils.java
  67. 17
      common/proto/src/main/proto/queue.proto
  68. 11
      common/queue/src/main/java/org/thingsboard/server/queue/discovery/TopicService.java
  69. 40
      common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaAdmin.java
  70. 11
      common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java
  71. 5
      common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaTopicConfigs.java
  72. 6
      common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java
  73. 4
      common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java
  74. 5
      common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java
  75. 28
      common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java
  76. 28
      common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java
  77. 18
      common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java
  78. 6
      common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java
  79. 10
      common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java
  80. 6
      common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java
  81. 4
      common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java
  82. 6
      common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java
  83. 4
      common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java
  84. 11
      common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java
  85. 8
      common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java
  86. 3
      common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java
  87. 8
      common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java
  88. 9
      common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineQueueFactory.java
  89. 8
      common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java
  90. 6
      common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java
  91. 75
      dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeEventService.java
  92. 5
      dao/src/main/java/org/thingsboard/server/dao/edge/DefaultEdgeSynchronizationManager.java
  93. 2
      dao/src/main/java/org/thingsboard/server/dao/edge/EdgeDao.java
  94. 2
      dao/src/main/java/org/thingsboard/server/dao/edge/EdgeEventDao.java
  95. 8
      dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java
  96. 81
      dao/src/main/java/org/thingsboard/server/dao/edge/PostgresEdgeEventService.java
  97. 1
      dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java
  98. 28
      dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java
  99. 30
      dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java
  100. 9
      dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java

137
application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java

@ -17,16 +17,20 @@ package org.thingsboard.server.service.edge;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.thingsboard.server.cache.limits.RateLimitService;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.dao.alarm.AlarmCommentService;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetProfileService;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService;
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.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.domain.DomainService;
@ -36,8 +40,10 @@ import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.notification.NotificationRuleService;
import org.thingsboard.server.dao.notification.NotificationTargetService;
import org.thingsboard.server.dao.notification.NotificationTemplateService;
import org.thingsboard.server.dao.oauth2.OAuth2ClientService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.settings.AdminSettingsService;
@ -49,6 +55,8 @@ import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.EdgeEventStorageSettings;
import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
import org.thingsboard.server.service.edge.rpc.constructor.asset.AssetMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.device.DeviceMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.edge.EdgeMsgConstructor;
import org.thingsboard.server.service.edge.rpc.processor.alarm.AlarmEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.alarm.AlarmEdgeProcessorFactory;
@ -83,155 +91,172 @@ import org.thingsboard.server.service.edge.rpc.processor.user.UserEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.widget.WidgetBundleEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.widget.WidgetTypeEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.sync.EdgeRequestsService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.executors.GrpcCallbackExecutorService;
@Lazy
@Data
@Component
@TbCoreComponent
@Data
@Lazy
public class EdgeContextComponent {
// services
@Autowired
private TbClusterService clusterService;
private AdminSettingsService adminSettingsService;
@Autowired
private EdgeService edgeService;
private AlarmCommentService alarmCommentService;
@Autowired(required = false)
private EdgeRpcService edgeRpcService;
@Autowired
private AlarmService alarmService;
@Autowired
private EdgeEventService edgeEventService;
private AssetProfileService assetProfileService;
@Autowired
private AdminSettingsService adminSettingsService;
private AssetService assetService;
@Autowired
private DeviceService deviceService;
private AttributesService attributesService;
@Autowired
private AssetService assetService;
private CustomerService customerService;
@Autowired
private EntityViewService entityViewService;
private DashboardService dashboardService;
@Autowired
private DeviceCredentialsService deviceCredentialsService;
@Autowired
private DeviceProfileService deviceProfileService;
@Autowired
private AssetProfileService assetProfileService;
private DeviceService deviceService;
@Autowired
private AttributesService attributesService;
private DomainService domainService;
@Autowired
private DashboardService dashboardService;
private EdgeEventService edgeEventService;
@Autowired
private RuleChainService ruleChainService;
private EdgeRequestsService edgeRequestsService;
@Autowired(required = false)
private EdgeRpcService edgeRpcService;
@Autowired
private UserService userService;
private EdgeService edgeService;
@Autowired
private CustomerService customerService;
private EntityViewService entityViewService;
@Autowired
private WidgetTypeService widgetTypeService;
private NotificationRuleService notificationRuleService;
@Autowired
private WidgetsBundleService widgetsBundleService;
private NotificationTargetService notificationTargetService;
@Autowired
private EdgeRequestsService edgeRequestsService;
private NotificationTemplateService notificationTemplateService;
@Autowired
private OAuth2ClientService oAuth2ClientService;
@Autowired
private OtaPackageService otaPackageService;
@Autowired
private TenantService tenantService;
private QueueService queueService;
@Autowired
private TenantProfileService tenantProfileService;
private RateLimitService rateLimitService;
@Autowired
private QueueService queueService;
private RelationService relationService;
@Autowired
private ResourceService resourceService;
@Autowired
private NotificationRuleService notificationRuleService;
private RuleChainService ruleChainService;
@Autowired
private NotificationTargetService notificationTargetService;
private TbClusterService clusterService;
@Autowired
private NotificationTemplateService notificationTemplateService;
private TenantProfileService tenantProfileService;
@Autowired
private DomainService domainService;
private TenantService tenantService;
@Autowired
private RateLimitService rateLimitService;
private UserService userService;
@Autowired
private NotificationRuleProcessor notificationRuleProcessor;
private WidgetTypeService widgetTypeService;
@Autowired
private WidgetsBundleService widgetsBundleService;
// processors
@Autowired
private AdminSettingsEdgeProcessor adminSettingsProcessor;
@Autowired
private AlarmEdgeProcessor alarmProcessor;
@Autowired
private DeviceProfileEdgeProcessor deviceProfileProcessor;
private AssetEdgeProcessor assetProcessor;
@Autowired
private AssetProfileEdgeProcessor assetProfileProcessor;
@Autowired
private EdgeProcessor edgeProcessor;
private CustomerEdgeProcessor customerProcessor;
@Autowired
private DeviceEdgeProcessor deviceProcessor;
private DashboardEdgeProcessor dashboardProcessor;
@Autowired
private AssetEdgeProcessor assetProcessor;
private DeviceEdgeProcessor deviceProcessor;
@Autowired
private EntityViewEdgeProcessor entityViewProcessor;
private DeviceProfileEdgeProcessor deviceProfileProcessor;
@Autowired
private UserEdgeProcessor userProcessor;
private EdgeProcessor edgeProcessor;
@Autowired
private RelationEdgeProcessor relationProcessor;
private EntityViewEdgeProcessor entityViewProcessor;
@Autowired
private TelemetryEdgeProcessor telemetryProcessor;
private NotificationEdgeProcessor notificationEdgeProcessor;
@Autowired
private DashboardEdgeProcessor dashboardProcessor;
private NotificationRuleProcessor notificationRuleProcessor;
@Autowired
private RuleChainEdgeProcessor ruleChainProcessor;
private OAuth2EdgeProcessor oAuth2EdgeProcessor;
@Autowired
private CustomerEdgeProcessor customerProcessor;
private OtaPackageEdgeProcessor otaPackageProcessor;
@Autowired
private WidgetBundleEdgeProcessor widgetBundleProcessor;
private QueueEdgeProcessor queueProcessor;
@Autowired
private WidgetTypeEdgeProcessor widgetTypeProcessor;
private RelationEdgeProcessor relationProcessor;
@Autowired
private AdminSettingsEdgeProcessor adminSettingsProcessor;
private ResourceEdgeProcessor resourceProcessor;
@Autowired
private OtaPackageEdgeProcessor otaPackageProcessor;
private RuleChainEdgeProcessor ruleChainProcessor;
@Autowired
private QueueEdgeProcessor queueProcessor;
private TelemetryEdgeProcessor telemetryProcessor;
@Autowired
private TenantEdgeProcessor tenantProcessor;
@ -240,23 +265,28 @@ public class EdgeContextComponent {
private TenantProfileEdgeProcessor tenantProfileProcessor;
@Autowired
private ResourceEdgeProcessor resourceProcessor;
private UserEdgeProcessor userProcessor;
@Autowired
private NotificationEdgeProcessor notificationEdgeProcessor;
private WidgetBundleEdgeProcessor widgetBundleProcessor;
@Autowired
private OAuth2EdgeProcessor oAuth2EdgeProcessor;
private WidgetTypeEdgeProcessor widgetTypeProcessor;
// msg constructors
@Autowired
private EdgeMsgConstructor edgeMsgConstructor;
// factories
@Autowired
private AlarmEdgeProcessorFactory alarmEdgeProcessorFactory;
@Autowired
private AssetEdgeProcessorFactory assetEdgeProcessorFactory;
@Autowired
private AssetMsgConstructorFactory assetMsgConstructorFactory;
@Autowired
private AssetProfileEdgeProcessorFactory assetProfileEdgeProcessorFactory;
@ -266,6 +296,9 @@ public class EdgeContextComponent {
@Autowired
private DeviceEdgeProcessorFactory deviceEdgeProcessorFactory;
@Autowired
private DeviceMsgConstructorFactory deviceMsgConstructorFactory;
@Autowired
private DeviceProfileEdgeProcessorFactory deviceProfileEdgeProcessorFactory;
@ -278,12 +311,12 @@ public class EdgeContextComponent {
@Autowired
private ResourceEdgeProcessorFactory resourceEdgeProcessorFactory;
// config
@Autowired
private EdgeEventStorageSettings edgeEventStorageSettings;
@Autowired
private DbCallbackExecutorService dbCallbackExecutor;
// callback
@Autowired
private GrpcCallbackExecutorService grpcCallbackExecutorService;
}

7
application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java

@ -65,14 +65,15 @@ import org.thingsboard.server.dao.tenant.TenantService;
* future.addCallback(eventPublisher.publishEvent(...))
* }
* */
@Slf4j
@Component
@RequiredArgsConstructor
@Slf4j
public class EdgeEventSourcingListener {
private final TbClusterService tbClusterService;
private final EdgeSynchronizationManager edgeSynchronizationManager;
private final TenantService tenantService;
private final EdgeSynchronizationManager edgeSynchronizationManager;
@PostConstruct
public void init() {
@ -106,7 +107,7 @@ public class EdgeEventSourcingListener {
return;
}
try {
if (EntityType.EDGE.equals(entityType) || EntityType.TENANT.equals(entityType)) {
if (EntityType.TENANT.equals(entityType) || EntityType.EDGE.equals(entityType)) {
return;
}
log.trace("[{}] DeleteEntityEvent called: {}", tenantId, event);

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

@ -58,9 +58,12 @@ import org.thingsboard.server.gen.edge.v1.EdgeRpcServiceGrpc;
import org.thingsboard.server.gen.edge.v1.RequestMsg;
import org.thingsboard.server.gen.edge.v1.ResponseMsg;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.discovery.TopicService;
import org.thingsboard.server.queue.kafka.TbKafkaSettings;
import org.thingsboard.server.queue.kafka.TbKafkaTopicConfigs;
import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.EdgeContextComponent;
import org.thingsboard.server.service.state.DefaultDeviceStateService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import java.io.IOException;
@ -68,6 +71,7 @@ import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -79,6 +83,10 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import static org.thingsboard.server.service.state.DefaultDeviceStateService.ACTIVITY_STATE;
import static org.thingsboard.server.service.state.DefaultDeviceStateService.LAST_CONNECT_TIME;
import static org.thingsboard.server.service.state.DefaultDeviceStateService.LAST_DISCONNECT_TIME;
@Service
@Slf4j
@ConditionalOnProperty(prefix = "edges", value = "enabled", havingValue = "true")
@ -90,6 +98,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
private final Map<EdgeId, Boolean> sessionNewEvents = new HashMap<>();
private final ConcurrentMap<EdgeId, ScheduledFuture<?>> sessionEdgeEventChecks = new ConcurrentHashMap<>();
private final ConcurrentMap<UUID, Consumer<FromEdgeSyncResponse>> localSyncEdgeRequests = new ConcurrentHashMap<>();
private final ConcurrentMap<EdgeId, Boolean> edgeEventsMigrationProcessed = new ConcurrentHashMap<>();
@Value("${edges.rpc.port}")
private int rpcPort;
@ -134,6 +143,18 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
@Autowired
private TbTransactionalCache<EdgeId, String> edgeIdServiceIdCache;
@Autowired
private TopicService topicService;
@Autowired
private TbCoreQueueFactory tbCoreQueueFactory;
@Autowired
private Optional<TbKafkaSettings> kafkaSettings;
@Autowired
private Optional<TbKafkaTopicConfigs> kafkaTopicConfigs;
private Server server;
private ScheduledExecutorService edgeEventProcessingExecutorService;
@ -202,13 +223,16 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
@Override
public StreamObserver<RequestMsg> handleMsgs(StreamObserver<ResponseMsg> outputStream) {
return new EdgeGrpcSession(ctx,
outputStream,
this::onEdgeConnect,
this::onEdgeDisconnect,
sendDownlinkExecutorService,
this.maxInboundMessageSize,
this.maxHighPriorityQueueSizePerSession).getInputStream();
EdgeGrpcSession session = createEdgeGrpcSession(outputStream);
return session.getInputStream();
}
private EdgeGrpcSession createEdgeGrpcSession(StreamObserver<ResponseMsg> outputStream) {
return kafkaSettings.isPresent() && kafkaTopicConfigs.isPresent()
? new KafkaEdgeGrpcSession(ctx, topicService, tbCoreQueueFactory, kafkaSettings.get(), kafkaTopicConfigs.get(), outputStream, this::onEdgeConnect, this::onEdgeDisconnect,
sendDownlinkExecutorService, maxInboundMessageSize, maxHighPriorityQueueSizePerSession)
: new PostgresEdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect,
sendDownlinkExecutorService, maxInboundMessageSize, maxHighPriorityQueueSizePerSession);
}
@Override
@ -253,6 +277,8 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
EdgeGrpcSession session = sessions.get(edgeId);
if (session != null && session.isConnected()) {
log.info("[{}] Closing and removing session for edge [{}]", tenantId, edgeId);
session.destroy();
session.cleanUp();
session.close();
sessions.remove(edgeId);
final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock());
@ -311,12 +337,13 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
} finally {
newEventLock.unlock();
}
save(tenantId, edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true);
save(tenantId, edgeId, ACTIVITY_STATE, true);
long lastConnectTs = System.currentTimeMillis();
save(tenantId, edgeId, DefaultDeviceStateService.LAST_CONNECT_TIME, lastConnectTs);
save(tenantId, edgeId, LAST_CONNECT_TIME, lastConnectTs);
edgeIdServiceIdCache.put(edgeId, serviceInfoProvider.getServiceId());
pushRuleEngineMessage(tenantId, edge, lastConnectTs, TbMsgType.CONNECT_EVENT);
cancelScheduleEdgeEventsCheck(edgeId);
edgeEventsMigrationProcessed.putIfAbsent(edgeId, Boolean.FALSE);
scheduleEdgeEventsCheck(edgeGrpcSession);
}
@ -377,7 +404,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
private void scheduleEdgeEventsCheck(EdgeGrpcSession session) {
EdgeId edgeId = session.getEdge().getId();
UUID tenantId = session.getEdge().getTenantId().getId();
TenantId tenantId = session.getEdge().getTenantId();
if (sessions.containsKey(edgeId)) {
ScheduledFuture<?> edgeEventCheckTask = edgeEventProcessingExecutorService.schedule(() -> {
try {
@ -387,6 +414,8 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
if (Boolean.TRUE.equals(sessionNewEvents.get(edgeId))) {
log.trace("[{}][{}] Set session new events flag to false", tenantId, edgeId.getId());
sessionNewEvents.put(edgeId, false);
processEdgeEventMigrationIfNeeded(session, edgeId);
session.processHighPriorityEvents();
Futures.addCallback(session.processEdgeEvents(), new FutureCallback<>() {
@Override
public void onSuccess(Boolean newEventsAdded) {
@ -420,6 +449,21 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
}
}
private void processEdgeEventMigrationIfNeeded(EdgeGrpcSession session, EdgeId edgeId) throws Exception {
boolean isMigrationProcessed = edgeEventsMigrationProcessed.getOrDefault(edgeId, Boolean.FALSE);
if (!isMigrationProcessed) {
Boolean eventsExist = session.migrateEdgeEvents().get();
if (Boolean.TRUE.equals(eventsExist)) {
sessionNewEvents.put(edgeId, true);
scheduleEdgeEventsCheck(session);
} else if (Boolean.FALSE.equals(eventsExist)) {
edgeEventsMigrationProcessed.put(edgeId, true);
} else {
scheduleEdgeEventsCheck(session);
}
}
}
private void cancelScheduleEdgeEventsCheck(EdgeId edgeId) {
log.trace("[{}] cancelling edge event check for edge", edgeId);
if (sessionEdgeEventChecks.containsKey(edgeId)) {
@ -444,10 +488,11 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
} finally {
newEventLock.unlock();
}
toRemove.destroy();
TenantId tenantId = toRemove.getEdge().getTenantId();
save(tenantId, edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false);
save(tenantId, edgeId, ACTIVITY_STATE, false);
long lastDisconnectTs = System.currentTimeMillis();
save(tenantId, edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, lastDisconnectTs);
save(tenantId, edgeId, LAST_DISCONNECT_TIME, lastDisconnectTs);
pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edge, lastDisconnectTs, TbMsgType.DISCONNECT_EVENT);
cancelScheduleEdgeEventsCheck(edgeId);
} else {
@ -481,6 +526,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
}
private static class AttributeSaveCallback implements FutureCallback<Void> {
private final TenantId tenantId;
private final EdgeId edgeId;
private final String key;
@ -502,6 +548,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
public void onFailure(Throwable t) {
log.warn("[{}][{}] Failed to update attribute [{}] with value [{}]", tenantId, edgeId, key, value, t);
}
}
private void pushRuleEngineMessage(TenantId tenantId, Edge edge, long ts, TbMsgType msgType) {
@ -510,11 +557,11 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
ObjectNode edgeState = JacksonUtil.newObjectNode();
boolean isConnected = TbMsgType.CONNECT_EVENT.equals(msgType);
if (isConnected) {
edgeState.put(DefaultDeviceStateService.ACTIVITY_STATE, true);
edgeState.put(DefaultDeviceStateService.LAST_CONNECT_TIME, ts);
edgeState.put(ACTIVITY_STATE, true);
edgeState.put(LAST_CONNECT_TIME, ts);
} else {
edgeState.put(DefaultDeviceStateService.ACTIVITY_STATE, false);
edgeState.put(DefaultDeviceStateService.LAST_DISCONNECT_TIME, ts);
edgeState.put(ACTIVITY_STATE, false);
edgeState.put(LAST_DISCONNECT_TIME, ts);
}
ctx.getNotificationRuleProcessor().process(EdgeConnectionTrigger.builder()
.tenantId(tenantId)

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

File diff suppressed because it is too large

55
application/src/main/java/org/thingsboard/server/service/edge/rpc/KafkaEdgeEventService.java

@ -0,0 +1,55 @@
/**
* Copyright © 2016-2024 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.rpc;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.util.ProtoUtils;
import org.thingsboard.server.dao.edge.BaseEdgeEventService;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.discovery.TopicService;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import java.util.UUID;
@Slf4j
@Service
@RequiredArgsConstructor
@ConditionalOnExpression("'${queue.type:null}'=='kafka'")
public class KafkaEdgeEventService extends BaseEdgeEventService {
private final TopicService topicService;
private final TbQueueProducerProvider producerProvider;
@Override
public ListenableFuture<Void> saveAsync(EdgeEvent edgeEvent) {
validateEdgeEvent(edgeEvent);
TopicPartitionInfo tpi = topicService.getEdgeEventNotificationsTopic(edgeEvent.getTenantId(), edgeEvent.getEdgeId());
ToEdgeEventNotificationMsg msg = ToEdgeEventNotificationMsg.newBuilder().setEdgeEventMsg(ProtoUtils.toProto(edgeEvent)).build();
producerProvider.getTbEdgeEventsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null);
return Futures.immediateFuture(null);
}
}

146
application/src/main/java/org/thingsboard/server/service/edge/rpc/KafkaEdgeGrpcSession.java

@ -0,0 +1,146 @@
/**
* Copyright © 2016-2024 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.rpc;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
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.util.ProtoUtils;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.ResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.queue.TbQueueConsumer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.common.consumer.QueueConsumerManager;
import org.thingsboard.server.queue.discovery.TopicService;
import org.thingsboard.server.queue.kafka.TbKafkaAdmin;
import org.thingsboard.server.queue.kafka.TbKafkaSettings;
import org.thingsboard.server.queue.kafka.TbKafkaTopicConfigs;
import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
import org.thingsboard.server.service.edge.EdgeContextComponent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.BiConsumer;
@Slf4j
public class KafkaEdgeGrpcSession extends EdgeGrpcSession {
private final TopicService topicService;
private final TbCoreQueueFactory tbCoreQueueFactory;
private final TbKafkaSettings kafkaSettings;
private final TbKafkaTopicConfigs kafkaTopicConfigs;
private volatile boolean isHighPriorityProcessing;
private QueueConsumerManager<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> consumer;
private ExecutorService consumerExecutor;
public KafkaEdgeGrpcSession(EdgeContextComponent ctx, TopicService topicService, TbCoreQueueFactory tbCoreQueueFactory,
TbKafkaSettings kafkaSettings, TbKafkaTopicConfigs kafkaTopicConfigs, StreamObserver<ResponseMsg> outputStream,
BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener, BiConsumer<Edge, UUID> sessionCloseListener,
ScheduledExecutorService sendDownlinkExecutorService, int maxInboundMessageSize, int maxHighPriorityQueueSizePerSession) {
super(ctx, outputStream, sessionOpenListener, sessionCloseListener, sendDownlinkExecutorService, maxInboundMessageSize, maxHighPriorityQueueSizePerSession);
this.topicService = topicService;
this.tbCoreQueueFactory = tbCoreQueueFactory;
this.kafkaSettings = kafkaSettings;
this.kafkaTopicConfigs = kafkaTopicConfigs;
}
private void processMsgs(List<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> msgs, TbQueueConsumer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> consumer) {
log.trace("[{}][{}] starting processing edge events", tenantId, sessionId);
if (isConnected() && isSyncCompleted() && !isHighPriorityProcessing) {
List<EdgeEvent> edgeEvents = new ArrayList<>();
for (TbProtoQueueMsg<ToEdgeEventNotificationMsg> msg : msgs) {
EdgeEvent edgeEvent = ProtoUtils.fromProto(msg.getValue().getEdgeEventMsg());
edgeEvents.add(edgeEvent);
}
List<DownlinkMsg> downlinkMsgsPack = convertToDownlinkMsgsPack(edgeEvents);
try {
boolean isInterrupted = sendDownlinkMsgsPack(downlinkMsgsPack).get();
if (isInterrupted) {
log.debug("[{}][{}][{}] Send downlink messages task was interrupted", tenantId, edge.getId(), sessionId);
} else {
consumer.commit();
}
} catch (Exception e) {
log.error("[{}] Failed to process all downlink messages", sessionId, e);
}
} else {
try {
Thread.sleep(ctx.getEdgeEventStorageSettings().getNoRecordsSleepInterval());
} catch (InterruptedException interruptedException) {
log.trace("Failed to wait until the server has capacity to handle new requests", interruptedException);
}
log.trace("[{}][{}] edge is not connected or sync is not completed. Skipping iteration", tenantId, sessionId);
}
}
@Override
public ListenableFuture<Boolean> migrateEdgeEvents() throws Exception {
return super.processEdgeEvents();
}
@Override
public ListenableFuture<Boolean> processEdgeEvents() {
if (consumer == null) {
this.consumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-event-consumer"));
this.consumer = QueueConsumerManager.<TbProtoQueueMsg<ToEdgeEventNotificationMsg>>builder()
.name("TB Edge events")
.msgPackProcessor(this::processMsgs)
.pollInterval(ctx.getEdgeEventStorageSettings().getNoRecordsSleepInterval())
.consumerCreator(() -> tbCoreQueueFactory.createEdgeEventMsgConsumer(tenantId, edge.getId()))
.consumerExecutor(consumerExecutor)
.threadPrefix("edge-events")
.build();
consumer.subscribe();
consumer.launch();
}
return Futures.immediateFuture(Boolean.FALSE);
}
@Override
public void processHighPriorityEvents() {
isHighPriorityProcessing = true;
super.processHighPriorityEvents();
isHighPriorityProcessing = false;
}
@Override
public void destroy() {
consumer.stop();
consumerExecutor.shutdown();
}
@Override
public void cleanUp() {
String topic = topicService.buildEdgeEventNotificationsTopicPartitionInfo(tenantId, edge.getId()).getTopic();
TbKafkaAdmin kafkaAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getEdgeEventConfigs());
kafkaAdmin.deleteTopic(topic);
}
}

46
application/src/main/java/org/thingsboard/server/service/edge/rpc/PostgresEdgeGrpcSession.java

@ -0,0 +1,46 @@
/**
* Copyright © 2016-2024 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.rpc;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.gen.edge.v1.ResponseMsg;
import org.thingsboard.server.service.edge.EdgeContextComponent;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.BiConsumer;
@Slf4j
public class PostgresEdgeGrpcSession extends EdgeGrpcSession {
PostgresEdgeGrpcSession(EdgeContextComponent ctx, StreamObserver<ResponseMsg> outputStream,
BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener,
BiConsumer<Edge, UUID> sessionCloseListener, ScheduledExecutorService sendDownlinkExecutorService,
int maxInboundMessageSize, int maxHighPriorityQueueSizePerSession) {
super(ctx, outputStream, sessionOpenListener, sessionCloseListener, sendDownlinkExecutorService, maxInboundMessageSize, maxHighPriorityQueueSizePerSession);
}
@Override
public ListenableFuture<Boolean> migrateEdgeEvents() {
return Futures.immediateFuture(Boolean.FALSE);
}
}

340
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java

@ -20,19 +20,10 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.AttributeScope;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@ -59,72 +50,15 @@ import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
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.dao.alarm.AlarmCommentService;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetProfileService;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService;
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.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.domain.DomainService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.edge.EdgeSynchronizationManager;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.notification.NotificationRuleService;
import org.thingsboard.server.dao.notification.NotificationTargetService;
import org.thingsboard.server.dao.notification.NotificationTemplateService;
import org.thingsboard.server.dao.oauth2.OAuth2ClientService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.tenant.TenantProfileService;
import org.thingsboard.server.dao.tenant.TenantService;
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.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.dao.entity.EntityDaoRegistry;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.TbQueueCallback;
import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.service.edge.rpc.constructor.alarm.AlarmMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.asset.AssetMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.customer.CustomerMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.dashboard.DashboardMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.device.DeviceMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.edge.EdgeMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.notification.NotificationMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.oauth2.OAuth2MsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.queue.QueueMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.relation.RelationMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.resource.ResourceMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.rule.RuleChainMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.settings.AdminSettingsMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.telemetry.EntityDataMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.tenant.TenantMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.user.UserMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.widget.WidgetMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.processor.alarm.AlarmEdgeProcessorFactory;
import org.thingsboard.server.service.edge.rpc.processor.asset.AssetEdgeProcessorFactory;
import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorFactory;
import org.thingsboard.server.service.entitiy.TbLogEntityActionService;
import org.thingsboard.server.service.edge.EdgeContextComponent;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.profile.TbAssetProfileCache;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.state.DefaultDeviceStateService;
import org.thingsboard.server.service.state.DeviceStateService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import java.util.ArrayList;
import java.util.List;
@ -142,201 +76,10 @@ public abstract class BaseEdgeProcessor {
protected static final Lock assetCreationLock = new ReentrantLock();
@Autowired
protected TelemetrySubscriptionService tsSubService;
protected EdgeContextComponent edgeCtx;
@Autowired
protected TbLogEntityActionService logEntityActionService;
@Autowired
protected RuleChainService ruleChainService;
@Autowired
protected AlarmService alarmService;
@Autowired
protected AlarmCommentService alarmCommentService;
@Autowired
protected DeviceService deviceService;
@Autowired
protected TbDeviceProfileCache deviceProfileCache;
@Autowired
protected TbAssetProfileCache assetProfileCache;
@Autowired
protected DashboardService dashboardService;
@Autowired
protected AssetService assetService;
@Autowired
protected EntityViewService entityViewService;
@Autowired
protected TenantService tenantService;
@Autowired
protected TenantProfileService tenantProfileService;
@Autowired
protected EdgeService edgeService;
@Autowired
protected CustomerService customerService;
@Autowired
protected UserService userService;
@Autowired
protected DeviceProfileService deviceProfileService;
@Autowired
protected AssetProfileService assetProfileService;
@Autowired
protected RelationService relationService;
@Autowired
protected DeviceCredentialsService deviceCredentialsService;
@Autowired
protected AttributesService attributesService;
@Autowired
protected TbClusterService tbClusterService;
@Autowired
protected DeviceStateService deviceStateService;
@Autowired
protected EdgeEventService edgeEventService;
@Autowired
protected WidgetsBundleService widgetsBundleService;
@Autowired
protected WidgetTypeService widgetTypeService;
@Autowired
protected OtaPackageService otaPackageService;
@Autowired
protected QueueService queueService;
@Autowired
protected PartitionService partitionService;
@Autowired
protected ResourceService resourceService;
@Autowired
protected NotificationRuleService notificationRuleService;
@Autowired
protected NotificationTargetService notificationTargetService;
@Autowired
protected NotificationTemplateService notificationTemplateService;
@Autowired
protected OAuth2ClientService oAuth2ClientService;
@Autowired
protected DomainService domainService;
@Autowired
@Lazy
protected TbQueueProducerProvider producerProvider;
@Autowired
protected DataValidator<Device> deviceValidator;
@Autowired
protected DataValidator<DeviceProfile> deviceProfileValidator;
@Autowired
protected DataValidator<Asset> assetValidator;
@Autowired
protected DataValidator<AssetProfile> assetProfileValidator;
@Autowired
protected DataValidator<Dashboard> dashboardValidator;
@Autowired
protected DataValidator<EntityView> entityViewValidator;
@Autowired
protected DataValidator<TbResource> resourceValidator;
@Autowired
protected EdgeMsgConstructor edgeMsgConstructor;
@Autowired
protected EntityDataMsgConstructor entityDataMsgConstructor;
@Autowired
protected NotificationMsgConstructor notificationMsgConstructor;
@Autowired
protected OAuth2MsgConstructor oAuth2MsgConstructor;
@Autowired
protected RuleChainMsgConstructorFactory ruleChainMsgConstructorFactory;
@Autowired
protected AlarmMsgConstructorFactory alarmMsgConstructorFactory;
@Autowired
protected DeviceMsgConstructorFactory deviceMsgConstructorFactory;
@Autowired
protected AssetMsgConstructorFactory assetMsgConstructorFactory;
@Autowired
protected EntityViewMsgConstructorFactory entityViewMsgConstructorFactory;
@Autowired
protected DashboardMsgConstructorFactory dashboardMsgConstructorFactory;
@Autowired
protected RelationMsgConstructorFactory relationMsgConstructorFactory;
@Autowired
protected UserMsgConstructorFactory userMsgConstructorFactory;
@Autowired
protected CustomerMsgConstructorFactory customerMsgConstructorFactory;
@Autowired
protected TenantMsgConstructorFactory tenantMsgConstructorFactory;
@Autowired
protected WidgetMsgConstructorFactory widgetMsgConstructorFactory;
@Autowired
protected AdminSettingsMsgConstructorFactory adminSettingsMsgConstructorFactory;
@Autowired
protected OtaPackageMsgConstructorFactory otaPackageMsgConstructorFactory;
@Autowired
protected QueueMsgConstructorFactory queueMsgConstructorFactory;
@Autowired
protected ResourceMsgConstructorFactory resourceMsgConstructorFactory;
@Autowired
protected AlarmEdgeProcessorFactory alarmEdgeProcessorFactory;
@Autowired
protected AssetEdgeProcessorFactory assetEdgeProcessorFactory;
@Autowired
protected EntityViewProcessorFactory entityViewProcessorFactory;
protected EntityDaoRegistry entityDaoRegistry;
@Autowired
protected EdgeSynchronizationManager edgeSynchronizationManager;
@ -351,7 +94,7 @@ public abstract class BaseEdgeProcessor {
EntityId entityId,
JsonNode body) {
ListenableFuture<Optional<AttributeKvEntry>> future =
attributesService.find(tenantId, edgeId, AttributeScope.SERVER_SCOPE, DefaultDeviceStateService.ACTIVITY_STATE);
edgeCtx.getAttributesService().find(tenantId, edgeId, AttributeScope.SERVER_SCOPE, DefaultDeviceStateService.ACTIVITY_STATE);
return Futures.transformAsync(future, activeOpt -> {
if (activeOpt.isEmpty()) {
log.trace("Edge is not activated. Skipping event. tenantId [{}], edgeId [{}], type[{}], " +
@ -376,11 +119,12 @@ public abstract class BaseEdgeProcessor {
private boolean doSaveIfEdgeIsOffline(EdgeEventType type, EdgeEventActionType action) {
return switch (action) {
case TIMESERIES_UPDATED, ALARM_ACK, ALARM_CLEAR, ALARM_ASSIGNED, ALARM_UNASSIGNED, ADDED_COMMENT, UPDATED_COMMENT ->
true;
case TIMESERIES_UPDATED, ALARM_ACK, ALARM_CLEAR, ALARM_ASSIGNED, ALARM_UNASSIGNED, ADDED_COMMENT,
UPDATED_COMMENT -> true;
default -> switch (type) {
case ALARM, ALARM_COMMENT, RULE_CHAIN, RULE_CHAIN_METADATA, USER, CUSTOMER, TENANT, TENANT_PROFILE, WIDGETS_BUNDLE, WIDGET_TYPE,
ADMIN_SETTINGS, OTA_PACKAGE, QUEUE, RELATION, NOTIFICATION_TEMPLATE, NOTIFICATION_TARGET, NOTIFICATION_RULE -> true;
case ALARM, ALARM_COMMENT, RULE_CHAIN, RULE_CHAIN_METADATA, USER, CUSTOMER, TENANT, TENANT_PROFILE,
WIDGETS_BUNDLE, WIDGET_TYPE, ADMIN_SETTINGS, OTA_PACKAGE, QUEUE, RELATION, NOTIFICATION_TEMPLATE, NOTIFICATION_TARGET,
NOTIFICATION_RULE -> true;
default -> false;
};
};
@ -391,8 +135,7 @@ public abstract class BaseEdgeProcessor {
tenantId, edgeId, type, action, entityId, body);
EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body);
return edgeEventService.saveAsync(edgeEvent);
return edgeCtx.getEdgeEventService().saveAsync(edgeEvent);
}
protected ListenableFuture<Void> processActionForAllEdges(TenantId tenantId, EdgeEventType type,
@ -400,7 +143,7 @@ public abstract class BaseEdgeProcessor {
JsonNode body, EdgeId sourceEdgeId) {
List<ListenableFuture<Void>> futures = new ArrayList<>();
if (TenantId.SYS_TENANT_ID.equals(tenantId)) {
PageDataIterable<TenantId> tenantIds = new PageDataIterable<>(link -> tenantService.findTenantsIds(link), 1024);
PageDataIterable<TenantId> tenantIds = new PageDataIterable<>(link -> edgeCtx.getTenantService().findTenantsIds(link), 1024);
for (TenantId tenantId1 : tenantIds) {
futures.addAll(processActionForAllEdgesByTenantId(tenantId1, type, actionType, entityId, body, sourceEdgeId));
}
@ -417,7 +160,7 @@ public abstract class BaseEdgeProcessor {
JsonNode body,
EdgeId sourceEdgeId) {
List<ListenableFuture<Void>> futures = new ArrayList<>();
PageDataIterable<Edge> edges = new PageDataIterable<>(link -> edgeService.findEdgesByTenantId(tenantId, link), 1024);
PageDataIterable<Edge> edges = new PageDataIterable<>(link -> edgeCtx.getEdgeService().findEdgesByTenantId(tenantId, link), 1024);
for (Edge edge : edges) {
if (!edge.getId().equals(sourceEdgeId)) {
futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, body));
@ -504,7 +247,7 @@ public abstract class BaseEdgeProcessor {
EdgeEventActionType actionType, EdgeId sourceEdgeId) {
List<ListenableFuture<Void>> futures = new ArrayList<>();
PageDataIterableByTenantIdEntityId<EdgeId> edgeIds =
new PageDataIterableByTenantIdEntityId<>(edgeService::findRelatedEdgeIdsByEntityId, tenantId, entityId, RELATED_EDGES_CACHE_ITEMS);
new PageDataIterableByTenantIdEntityId<>(edgeCtx.getEdgeService()::findRelatedEdgeIdsByEntityId, tenantId, entityId, RELATED_EDGES_CACHE_ITEMS);
for (EdgeId relatedEdgeId : edgeIds) {
if (!relatedEdgeId.equals(sourceEdgeId)) {
futures.add(saveEdgeEvent(tenantId, relatedEdgeId, type, actionType, entityId, null));
@ -515,10 +258,10 @@ public abstract class BaseEdgeProcessor {
private ListenableFuture<Void> updateDependentRuleChains(TenantId tenantId, RuleChainId processingRuleChainId, EdgeId edgeId) {
List<ListenableFuture<Void>> futures = new ArrayList<>();
PageDataIterable<RuleChain> ruleChains = new PageDataIterable<>(link -> ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, link), 1024);
PageDataIterable<RuleChain> ruleChains = new PageDataIterable<>(link -> edgeCtx.getRuleChainService().findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, link), 1024);
for (RuleChain ruleChain : ruleChains) {
List<RuleChainConnectionInfo> connectionInfos =
ruleChainService.loadRuleChainMetaData(ruleChain.getTenantId(), ruleChain.getId()).getRuleChainConnections();
edgeCtx.getRuleChainService().loadRuleChainMetaData(ruleChain.getTenantId(), ruleChain.getId()).getRuleChainConnections();
if (connectionInfos != null && !connectionInfos.isEmpty()) {
for (RuleChainConnectionInfo connectionInfo : connectionInfos) {
if (connectionInfo.getTargetRuleChainId().equals(processingRuleChainId)) {
@ -576,17 +319,7 @@ public abstract class BaseEdgeProcessor {
}
protected boolean isEntityExists(TenantId tenantId, EntityId entityId) {
return switch (entityId.getEntityType()) {
case TENANT -> tenantService.findTenantById(tenantId) != null;
case DEVICE -> deviceService.findDeviceById(tenantId, new DeviceId(entityId.getId())) != null;
case ASSET -> assetService.findAssetById(tenantId, new AssetId(entityId.getId())) != null;
case ENTITY_VIEW -> entityViewService.findEntityViewById(tenantId, new EntityViewId(entityId.getId())) != null;
case CUSTOMER -> customerService.findCustomerById(tenantId, new CustomerId(entityId.getId())) != null;
case USER -> userService.findUserById(tenantId, new UserId(entityId.getId())) != null;
case DASHBOARD -> dashboardService.findDashboardById(tenantId, new DashboardId(entityId.getId())) != null;
case EDGE -> edgeService.findEdgeById(tenantId, new EdgeId(entityId.getId())) != null;
default -> false;
};
return entityDaoRegistry.getDao(entityId.getEntityType()).existsById(tenantId, entityId.getId());
}
protected void createRelationFromEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId) {
@ -595,7 +328,7 @@ public abstract class BaseEdgeProcessor {
relation.setTo(entityId);
relation.setTypeGroup(RelationTypeGroup.COMMON);
relation.setType(EntityRelation.EDGE_TYPE);
relationService.saveRelation(tenantId, relation);
edgeCtx.getRelationService().saveRelation(tenantId, relation);
}
protected TbMsgMetaData getEdgeActionTbMsgMetaData(Edge edge, CustomerId customerId) {
@ -611,7 +344,7 @@ public abstract class BaseEdgeProcessor {
protected void pushEntityEventToRuleEngine(TenantId tenantId, EntityId entityId, CustomerId customerId,
TbMsgType msgType, String msgData, TbMsgMetaData metaData) {
TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, msgData);
tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, new TbQueueCallback() {
edgeCtx.getClusterService().pushMsgToRuleEngine(tenantId, entityId, tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, msgData);
@ -624,39 +357,4 @@ public abstract class BaseEdgeProcessor {
});
}
protected AssetProfile checkIfAssetProfileDefaultFieldsAssignedToEdge(TenantId tenantId, EdgeId edgeId, AssetProfile assetProfile, EdgeVersion edgeVersion) {
if (EdgeVersion.V_3_3_0.equals(edgeVersion) || EdgeVersion.V_3_3_3.equals(edgeVersion) || EdgeVersion.V_3_4_0.equals(edgeVersion)) {
if (assetProfile.getDefaultDashboardId() != null && isEntityNotAssignedToEdge(tenantId, assetProfile.getDefaultDashboardId(), edgeId)) {
assetProfile.setDefaultDashboardId(null);
}
if (assetProfile.getDefaultEdgeRuleChainId() != null && isEntityNotAssignedToEdge(tenantId, assetProfile.getDefaultEdgeRuleChainId(), edgeId)) {
assetProfile.setDefaultEdgeRuleChainId(null);
}
}
return assetProfile;
}
protected DeviceProfile checkIfDeviceProfileDefaultFieldsAssignedToEdge(TenantId tenantId, EdgeId edgeId, DeviceProfile deviceProfile, EdgeVersion edgeVersion) {
if (EdgeVersion.V_3_3_0.equals(edgeVersion) || EdgeVersion.V_3_3_3.equals(edgeVersion) || EdgeVersion.V_3_4_0.equals(edgeVersion)) {
if (deviceProfile.getDefaultDashboardId() != null && isEntityNotAssignedToEdge(tenantId, deviceProfile.getDefaultDashboardId(), edgeId)) {
deviceProfile.setDefaultDashboardId(null);
}
if (deviceProfile.getDefaultEdgeRuleChainId() != null && isEntityNotAssignedToEdge(tenantId, deviceProfile.getDefaultEdgeRuleChainId(), edgeId)) {
deviceProfile.setDefaultEdgeRuleChainId(null);
}
}
return deviceProfile;
}
private boolean isEntityNotAssignedToEdge(TenantId tenantId, EntityId entityId, EdgeId edgeId) {
PageDataIterableByTenantIdEntityId<EdgeId> edgeIds =
new PageDataIterableByTenantIdEntityId<>(edgeService::findRelatedEdgeIdsByEntityId, tenantId, entityId, RELATED_EDGES_CACHE_ITEMS);
for (EdgeId edgeId1 : edgeIds) {
if (edgeId1.equals(edgeId)) {
return false;
}
}
return true;
}
}

42
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessor.java

@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.alarm.Alarm;
@ -31,6 +32,7 @@ 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.PageDataIterableByTenantIdEntityId;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.gen.edge.v1.AlarmCommentUpdateMsg;
import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
@ -38,6 +40,7 @@ import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.service.edge.rpc.constructor.alarm.AlarmMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.alarm.AlarmMsgConstructorFactory;
import java.util.ArrayList;
import java.util.List;
@ -48,6 +51,12 @@ import static org.thingsboard.server.dao.edge.BaseRelatedEdgesService.RELATED_ED
@Slf4j
public abstract class AlarmEdgeProcessor extends BaseAlarmProcessor implements AlarmProcessor {
@Autowired
private AlarmMsgConstructorFactory alarmMsgConstructorFactory;
@Autowired
private EntityService entityService;
@Override
public ListenableFuture<Void> processAlarmMsgFromEdge(TenantId tenantId, EdgeId edgeId, AlarmUpdateMsg alarmUpdateMsg) {
log.trace("[{}] processAlarmMsgFromEdge [{}]", tenantId, alarmUpdateMsg);
@ -86,6 +95,7 @@ public abstract class AlarmEdgeProcessor extends BaseAlarmProcessor implements A
@Override
public DownlinkMsg convertAlarmCommentEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
var msgConstructor = (AlarmMsgConstructor) alarmMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED_COMMENT:
case UPDATED_COMMENT:
@ -94,8 +104,7 @@ public abstract class AlarmEdgeProcessor extends BaseAlarmProcessor implements A
if (alarmComment != null) {
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addAlarmCommentUpdateMsg(((AlarmMsgConstructor) alarmMsgConstructorFactory
.getMsgConstructorByEdgeVersion(edgeVersion)).constructAlarmCommentUpdatedMsg(msgType, alarmComment))
.addAlarmCommentUpdateMsg(msgConstructor.constructAlarmCommentUpdatedMsg(msgType, alarmComment))
.build();
}
default:
@ -116,7 +125,7 @@ public abstract class AlarmEdgeProcessor extends BaseAlarmProcessor implements A
alarmId, actionType, JacksonUtil.valueToTree(deletedAlarm), originatorEdgeId, EdgeEventType.ALARM);
return Futures.transform(Futures.allAsList(delFutures), voids -> null, dbCallbackExecutorService);
}
ListenableFuture<Alarm> alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId);
ListenableFuture<Alarm> alarmFuture = edgeCtx.getAlarmService().findAlarmByIdAsync(tenantId, alarmId);
return Futures.transformAsync(alarmFuture, alarm -> {
if (alarm == null) {
return Futures.immediateFuture(null);
@ -139,7 +148,7 @@ public abstract class AlarmEdgeProcessor extends BaseAlarmProcessor implements A
if (alarmComment == null) {
return Futures.immediateFuture(null);
}
Alarm alarmById = alarmService.findAlarmById(tenantId, new AlarmId(alarmComment.getAlarmId().getId()));
Alarm alarmById = edgeCtx.getAlarmService().findAlarmById(tenantId, new AlarmId(alarmComment.getAlarmId().getId()));
List<ListenableFuture<Void>> delFutures = pushEventToAllRelatedEdges(tenantId, alarmById.getOriginator(),
alarmId, actionType, JacksonUtil.valueToTree(alarmComment), originatorEdgeId, EdgeEventType.ALARM_COMMENT);
return Futures.transform(Futures.allAsList(delFutures), voids -> null, dbCallbackExecutorService);
@ -150,7 +159,7 @@ public abstract class AlarmEdgeProcessor extends BaseAlarmProcessor implements A
EdgeEventType edgeEventType) {
List<ListenableFuture<Void>> futures = new ArrayList<>();
PageDataIterableByTenantIdEntityId<EdgeId> edgeIds =
new PageDataIterableByTenantIdEntityId<>(edgeService::findRelatedEdgeIdsByEntityId, tenantId, originatorId, RELATED_EDGES_CACHE_ITEMS);
new PageDataIterableByTenantIdEntityId<>(edgeCtx.getEdgeService()::findRelatedEdgeIdsByEntityId, tenantId, originatorId, RELATED_EDGES_CACHE_ITEMS);
for (EdgeId relatedEdgeId : edgeIds) {
if (!relatedEdgeId.equals(sourceEdgeId)) {
futures.add(saveEdgeEvent(tenantId, relatedEdgeId, edgeEventType, actionType, alarmId, body));
@ -159,4 +168,27 @@ public abstract class AlarmEdgeProcessor extends BaseAlarmProcessor implements A
return futures;
}
private AlarmUpdateMsg convertAlarmEventToAlarmMsg(TenantId tenantId, UUID entityId, EdgeEventActionType actionType, JsonNode body, EdgeVersion edgeVersion) {
AlarmId alarmId = new AlarmId(entityId);
UpdateMsgType msgType = getUpdateMsgType(actionType);
var msgConstructor = (AlarmMsgConstructor) alarmMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
switch (actionType) {
case ADDED, UPDATED, ALARM_ACK, ALARM_CLEAR -> {
Alarm alarm = edgeCtx.getAlarmService().findAlarmById(tenantId, alarmId);
if (alarm != null) {
return msgConstructor.constructAlarmUpdatedMsg(msgType, alarm,
entityService.fetchEntityName(tenantId, alarm.getOriginator()).orElse(null));
}
}
case ALARM_DELETE, DELETED -> {
Alarm deletedAlarm = JacksonUtil.convertValue(body, Alarm.class);
if (deletedAlarm != null) {
return msgConstructor.constructAlarmUpdatedMsg(msgType, deletedAlarm,
entityService.fetchEntityName(tenantId, deletedAlarm.getOriginator()).orElse(null));
}
}
}
return null;
}
}

6
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessorV1.java

@ -59,9 +59,9 @@ public class AlarmEdgeProcessorV1 extends AlarmEdgeProcessor {
private EntityId getAlarmOriginator(TenantId tenantId, String entityName, EntityType entityType) {
return switch (entityType) {
case DEVICE -> deviceService.findDeviceByTenantIdAndName(tenantId, entityName).getId();
case ASSET -> assetService.findAssetByTenantIdAndName(tenantId, entityName).getId();
case ENTITY_VIEW -> entityViewService.findEntityViewByTenantIdAndName(tenantId, entityName).getId();
case DEVICE -> edgeCtx.getDeviceService().findDeviceByTenantIdAndName(tenantId, entityName).getId();
case ASSET -> edgeCtx.getAssetService().findAssetByTenantIdAndName(tenantId, entityName).getId();
case ENTITY_VIEW -> edgeCtx.getEntityViewService().findEntityViewByTenantIdAndName(tenantId, entityName).getId();
default -> null;
};
}

82
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java

@ -15,32 +15,21 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.alarm;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest;
import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.alarm.AlarmCommentDao;
import org.thingsboard.server.gen.edge.v1.AlarmCommentUpdateMsg;
import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg;
import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.service.edge.rpc.constructor.alarm.AlarmMsgConstructor;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
import java.util.UUID;
@ -66,27 +55,27 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor {
try {
switch (alarmUpdateMsg.getMsgType()) {
case ENTITY_CREATED_RPC_MESSAGE:
alarmService.createAlarm(AlarmCreateOrUpdateActiveRequest.fromAlarm(alarm, null, alarmId));
edgeCtx.getAlarmService().createAlarm(AlarmCreateOrUpdateActiveRequest.fromAlarm(alarm, null, alarmId));
break;
case ENTITY_UPDATED_RPC_MESSAGE:
alarmService.updateAlarm(AlarmUpdateRequest.fromAlarm(alarm));
edgeCtx.getAlarmService().updateAlarm(AlarmUpdateRequest.fromAlarm(alarm));
break;
case ALARM_ACK_RPC_MESSAGE:
Alarm alarmToAck = alarmService.findAlarmById(tenantId, alarmId);
Alarm alarmToAck = edgeCtx.getAlarmService().findAlarmById(tenantId, alarmId);
if (alarmToAck != null) {
alarmService.acknowledgeAlarm(tenantId, alarmId, alarm.getAckTs());
edgeCtx.getAlarmService().acknowledgeAlarm(tenantId, alarmId, alarm.getAckTs());
}
break;
case ALARM_CLEAR_RPC_MESSAGE:
Alarm alarmToClear = alarmService.findAlarmById(tenantId, alarmId);
Alarm alarmToClear = edgeCtx.getAlarmService().findAlarmById(tenantId, alarmId);
if (alarmToClear != null) {
alarmService.clearAlarm(tenantId, alarmId, alarm.getClearTs(), alarm.getDetails());
edgeCtx.getAlarmService().clearAlarm(tenantId, alarmId, alarm.getClearTs(), alarm.getDetails());
}
break;
case ENTITY_DELETED_RPC_MESSAGE:
Alarm alarmToDelete = alarmService.findAlarmById(tenantId, alarmId);
Alarm alarmToDelete = edgeCtx.getAlarmService().findAlarmById(tenantId, alarmId);
if (alarmToDelete != null) {
alarmService.delAlarm(tenantId, alarmId);
edgeCtx.getAlarmService().delAlarm(tenantId, alarmId);
}
break;
case UNRECOGNIZED:
@ -107,7 +96,7 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor {
throw new RuntimeException("[{" + tenantId + "}] alarmCommentUpdateMsg {" + alarmCommentUpdateMsg + "} cannot be converted to alarm comment");
}
try {
Alarm alarm = alarmService.findAlarmById(tenantId, new AlarmId(alarmComment.getAlarmId().getId()));
Alarm alarm = edgeCtx.getAlarmService().findAlarmById(tenantId, new AlarmId(alarmComment.getAlarmId().getId()));
if (alarm == null) {
return Futures.immediateFuture(null);
}
@ -116,12 +105,12 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor {
alarmCommentDao.save(tenantId, alarmComment);
break;
case ENTITY_UPDATED_RPC_MESSAGE:
alarmCommentService.createOrUpdateAlarmComment(tenantId, alarmComment);
edgeCtx.getAlarmCommentService().createOrUpdateAlarmComment(tenantId, alarmComment);
break;
case ENTITY_DELETED_RPC_MESSAGE:
AlarmComment alarmCommentToDelete = alarmCommentService.findAlarmCommentById(tenantId, alarmComment.getId());
AlarmComment alarmCommentToDelete = edgeCtx.getAlarmCommentService().findAlarmCommentById(tenantId, alarmComment.getId());
if (alarmCommentToDelete != null) {
alarmCommentService.saveAlarmComment(tenantId, alarmCommentToDelete);
edgeCtx.getAlarmCommentService().saveAlarmComment(tenantId, alarmCommentToDelete);
}
break;
case UNRECOGNIZED:
@ -140,51 +129,4 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor {
protected abstract Alarm constructAlarmFromUpdateMsg(TenantId tenantId, AlarmId alarmId, EntityId originatorId, AlarmUpdateMsg alarmUpdateMsg);
protected AlarmUpdateMsg convertAlarmEventToAlarmMsg(TenantId tenantId, UUID entityId, EdgeEventActionType actionType, JsonNode body, EdgeVersion edgeVersion) {
AlarmId alarmId = new AlarmId(entityId);
UpdateMsgType msgType = getUpdateMsgType(actionType);
switch (actionType) {
case ADDED, UPDATED, ALARM_ACK, ALARM_CLEAR -> {
Alarm alarm = alarmService.findAlarmById(tenantId, alarmId);
if (alarm != null) {
return ((AlarmMsgConstructor) alarmMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion))
.constructAlarmUpdatedMsg(msgType, alarm, findOriginatorEntityName(tenantId, alarm));
}
}
case ALARM_DELETE, DELETED -> {
Alarm deletedAlarm = JacksonUtil.convertValue(body, Alarm.class);
if (deletedAlarm != null) {
return ((AlarmMsgConstructor) alarmMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion))
.constructAlarmUpdatedMsg(msgType, deletedAlarm, findOriginatorEntityName(tenantId, deletedAlarm));
}
}
}
return null;
}
private String findOriginatorEntityName(TenantId tenantId, Alarm alarm) {
String entityName = null;
switch (alarm.getOriginator().getEntityType()) {
case DEVICE -> {
Device deviceById = deviceService.findDeviceById(tenantId, new DeviceId(alarm.getOriginator().getId()));
if (deviceById != null) {
entityName = deviceById.getName();
}
}
case ASSET -> {
Asset assetById = assetService.findAssetById(tenantId, new AssetId(alarm.getOriginator().getId()));
if (assetById != null) {
entityName = assetById.getName();
}
}
case ENTITY_VIEW -> {
EntityView entityViewById = entityViewService.findEntityViewById(tenantId, new EntityViewId(alarm.getOriginator().getId()));
if (entityViewById != null) {
entityName = entityViewById.getName();
}
}
}
return entityName;
}
}

36
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java

@ -28,7 +28,6 @@ import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -57,9 +56,9 @@ public abstract class AssetEdgeProcessor extends BaseAssetProcessor implements A
saveOrUpdateAsset(tenantId, assetId, assetUpdateMsg, edge);
return Futures.immediateFuture(null);
case ENTITY_DELETED_RPC_MESSAGE:
Asset assetToDelete = assetService.findAssetById(tenantId, assetId);
Asset assetToDelete = edgeCtx.getAssetService().findAssetById(tenantId, assetId);
if (assetToDelete != null) {
assetService.unassignAssetFromEdge(tenantId, assetId, edge.getId());
edgeCtx.getAssetService().unassignAssetFromEdge(tenantId, assetId, edge.getId());
}
return Futures.immediateFuture(null);
case UNRECOGNIZED:
@ -84,7 +83,7 @@ public abstract class AssetEdgeProcessor extends BaseAssetProcessor implements A
if (created) {
createRelationFromEdge(tenantId, edge.getId(), assetId);
pushAssetCreatedEventToRuleEngine(tenantId, edge, assetId);
assetService.assignAssetToEdge(tenantId, assetId, edge.getId());
edgeCtx.getAssetService().assignAssetToEdge(tenantId, assetId, edge.getId());
}
Boolean assetNameUpdated = resultPair.getSecond();
if (assetNameUpdated) {
@ -94,7 +93,7 @@ public abstract class AssetEdgeProcessor extends BaseAssetProcessor implements A
private void pushAssetCreatedEventToRuleEngine(TenantId tenantId, Edge edge, AssetId assetId) {
try {
Asset asset = assetService.findAssetById(tenantId, assetId);
Asset asset = edgeCtx.getAssetService().findAssetById(tenantId, assetId);
String assetAsString = JacksonUtil.toString(asset);
TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, asset.getCustomerId());
pushEntityEventToRuleEngine(tenantId, assetId, asset.getCustomerId(), TbMsgType.ENTITY_CREATED, assetAsString, msgMetaData);
@ -104,34 +103,33 @@ public abstract class AssetEdgeProcessor extends BaseAssetProcessor implements A
}
@Override
public DownlinkMsg convertAssetEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion) {
public DownlinkMsg convertAssetEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
AssetId assetId = new AssetId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (AssetMsgConstructor) assetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
var msgConstructor = (AssetMsgConstructor) edgeCtx.getAssetMsgConstructorFactory().getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED, ASSIGNED_TO_EDGE, ASSIGNED_TO_CUSTOMER, UNASSIGNED_FROM_CUSTOMER -> {
Asset asset = assetService.findAssetById(edgeEvent.getTenantId(), assetId);
Asset asset = edgeCtx.getAssetService().findAssetById(edgeEvent.getTenantId(), assetId);
if (asset != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
AssetUpdateMsg assetUpdateMsg = ((AssetMsgConstructor)
assetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructAssetUpdatedMsg(msgType, asset);
AssetUpdateMsg assetUpdateMsg = msgConstructor.constructAssetUpdatedMsg(msgType, asset);
DownlinkMsg.Builder builder = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addAssetUpdateMsg(assetUpdateMsg);
if (UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE.equals(msgType)) {
AssetProfile assetProfile = assetProfileService.findAssetProfileById(edgeEvent.getTenantId(), asset.getAssetProfileId());
assetProfile = checkIfAssetProfileDefaultFieldsAssignedToEdge(edgeEvent.getTenantId(), edgeId, assetProfile, edgeVersion);
AssetProfile assetProfile = edgeCtx.getAssetProfileService().findAssetProfileById(edgeEvent.getTenantId(), asset.getAssetProfileId());
builder.addAssetProfileUpdateMsg(msgConstructor.constructAssetProfileUpdatedMsg(msgType, assetProfile));
}
downlinkMsg = builder.build();
return builder.build();
}
}
case DELETED, UNASSIGNED_FROM_EDGE -> downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addAssetUpdateMsg(msgConstructor.constructAssetDeleteMsg(assetId))
.build();
case DELETED, UNASSIGNED_FROM_EDGE -> {
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addAssetUpdateMsg(msgConstructor.constructAssetDeleteMsg(assetId))
.build();
}
}
return downlinkMsg;
return null;
}
}

3
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProcessor.java

@ -18,7 +18,6 @@ package org.thingsboard.server.service.edge.rpc.processor.asset;
import com.google.common.util.concurrent.ListenableFuture;
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.TenantId;
import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
@ -29,6 +28,6 @@ public interface AssetProcessor extends EdgeProcessor {
ListenableFuture<Void> processAssetMsgFromEdge(TenantId tenantId, Edge edge, AssetUpdateMsg assetUpdateMsg);
DownlinkMsg convertAssetEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion);
DownlinkMsg convertAssetEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion);
}

11
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProcessor.java

@ -16,18 +16,23 @@
package org.thingsboard.server.service.edge.rpc.processor.asset;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
public abstract class BaseAssetProcessor extends BaseEdgeProcessor {
@Autowired
private DataValidator<Asset> assetValidator;
protected Pair<Boolean, Boolean> saveOrUpdateAsset(TenantId tenantId, AssetId assetId, AssetUpdateMsg assetUpdateMsg) {
boolean created = false;
boolean assetNameUpdated = false;
@ -37,7 +42,7 @@ public abstract class BaseAssetProcessor extends BaseEdgeProcessor {
if (asset == null) {
throw new RuntimeException("[{" + tenantId + "}] assetUpdateMsg {" + assetUpdateMsg + " } cannot be converted to asset");
}
Asset assetById = assetService.findAssetById(tenantId, assetId);
Asset assetById = edgeCtx.getAssetService().findAssetById(tenantId, assetId);
if (assetById == null) {
created = true;
asset.setId(null);
@ -45,7 +50,7 @@ public abstract class BaseAssetProcessor extends BaseEdgeProcessor {
asset.setId(assetId);
}
String assetName = asset.getName();
Asset assetByName = assetService.findAssetByTenantIdAndName(tenantId, assetName);
Asset assetByName = edgeCtx.getAssetService().findAssetByTenantIdAndName(tenantId, assetName);
if (assetByName != null && !assetByName.getId().equals(assetId)) {
assetName = assetName + "_" + StringUtils.randomAlphanumeric(15);
log.warn("[{}] Asset with name {} already exists. Renaming asset name to {}",
@ -59,7 +64,7 @@ public abstract class BaseAssetProcessor extends BaseEdgeProcessor {
if (created) {
asset.setId(assetId);
}
assetService.saveAsset(asset, false);
edgeCtx.getAssetService().saveAsset(asset, false);
} catch (Exception e) {
log.error("[{}] Failed to process asset update msg [{}]", tenantId, assetUpdateMsg, e);
throw e;

36
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/profile/AssetProfileEdgeProcessor.java

@ -50,16 +50,13 @@ public abstract class AssetProfileEdgeProcessor extends BaseAssetProfileProcesso
try {
edgeSynchronizationManager.getEdgeId().set(edge.getId());
switch (assetProfileUpdateMsg.getMsgType()) {
case ENTITY_CREATED_RPC_MESSAGE:
case ENTITY_UPDATED_RPC_MESSAGE:
return switch (assetProfileUpdateMsg.getMsgType()) {
case ENTITY_CREATED_RPC_MESSAGE, ENTITY_UPDATED_RPC_MESSAGE -> {
saveOrUpdateAssetProfile(tenantId, assetProfileId, assetProfileUpdateMsg, edge);
return Futures.immediateFuture(null);
case ENTITY_DELETED_RPC_MESSAGE:
case UNRECOGNIZED:
default:
return handleUnsupportedMsgType(assetProfileUpdateMsg.getMsgType());
}
yield Futures.immediateFuture(null);
}
default -> handleUnsupportedMsgType(assetProfileUpdateMsg.getMsgType());
};
} catch (DataValidationException e) {
log.warn("[{}] Failed to process AssetProfileUpdateMsg from Edge [{}]", tenantId, assetProfileUpdateMsg, e);
return Futures.immediateFailedFuture(e);
@ -83,7 +80,7 @@ public abstract class AssetProfileEdgeProcessor extends BaseAssetProfileProcesso
private void pushAssetProfileCreatedEventToRuleEngine(TenantId tenantId, Edge edge, AssetProfileId assetProfileId) {
try {
AssetProfile assetProfile = assetProfileService.findAssetProfileById(tenantId, assetProfileId);
AssetProfile assetProfile = edgeCtx.getAssetProfileService().findAssetProfileById(tenantId, assetProfileId);
String assetProfileAsString = JacksonUtil.toString(assetProfile);
TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null);
pushEntityEventToRuleEngine(tenantId, assetProfileId, null, TbMsgType.ENTITY_CREATED, assetProfileAsString, msgMetaData);
@ -93,33 +90,30 @@ public abstract class AssetProfileEdgeProcessor extends BaseAssetProfileProcesso
}
@Override
public DownlinkMsg convertAssetProfileEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion) {
public DownlinkMsg convertAssetProfileEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
AssetProfileId assetProfileId = new AssetProfileId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (AssetMsgConstructor) edgeCtx.getAssetMsgConstructorFactory().getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
AssetProfile assetProfile = assetProfileService.findAssetProfileById(edgeEvent.getTenantId(), assetProfileId);
AssetProfile assetProfile = edgeCtx.getAssetProfileService().findAssetProfileById(edgeEvent.getTenantId(), assetProfileId);
if (assetProfile != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
assetProfile = checkIfAssetProfileDefaultFieldsAssignedToEdge(edgeEvent.getTenantId(), edgeId, assetProfile, edgeVersion);
AssetProfileUpdateMsg assetProfileUpdateMsg = ((AssetMsgConstructor)
assetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructAssetProfileUpdatedMsg(msgType, assetProfile);
downlinkMsg = DownlinkMsg.newBuilder()
AssetProfileUpdateMsg assetProfileUpdateMsg = msgConstructor.constructAssetProfileUpdatedMsg(msgType, assetProfile);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addAssetProfileUpdateMsg(assetProfileUpdateMsg)
.build();
}
}
case DELETED -> {
AssetProfileUpdateMsg assetProfileUpdateMsg = ((AssetMsgConstructor)
assetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructAssetProfileDeleteMsg(assetProfileId);
downlinkMsg = DownlinkMsg.newBuilder()
AssetProfileUpdateMsg assetProfileUpdateMsg = msgConstructor.constructAssetProfileDeleteMsg(assetProfileId);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addAssetProfileUpdateMsg(assetProfileUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/profile/AssetProfileProcessor.java

@ -18,7 +18,6 @@ package org.thingsboard.server.service.edge.rpc.processor.asset.profile;
import com.google.common.util.concurrent.ListenableFuture;
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.TenantId;
import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
@ -29,5 +28,6 @@ public interface AssetProfileProcessor extends EdgeProcessor {
ListenableFuture<Void> processAssetProfileMsgFromEdge(TenantId tenantId, Edge edge, AssetProfileUpdateMsg assetProfileUpdateMsg);
DownlinkMsg convertAssetProfileEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion);
DownlinkMsg convertAssetProfileEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion);
}

12
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/profile/BaseAssetProfileProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.asset.profile;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.asset.AssetProfile;
@ -23,12 +24,16 @@ import org.thingsboard.server.common.data.id.AssetProfileId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor {
@Autowired
private DataValidator<AssetProfile> assetProfileValidator;
protected Pair<Boolean, Boolean> saveOrUpdateAssetProfile(TenantId tenantId, AssetProfileId assetProfileId, AssetProfileUpdateMsg assetProfileUpdateMsg) {
boolean created = false;
boolean assetProfileNameUpdated = false;
@ -38,7 +43,7 @@ public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor {
if (assetProfile == null) {
throw new RuntimeException("[{" + tenantId + "}] assetProfileUpdateMsg {" + assetProfileUpdateMsg + "} cannot be converted to asset profile");
}
AssetProfile assetProfileById = assetProfileService.findAssetProfileById(tenantId, assetProfileId);
AssetProfile assetProfileById = edgeCtx.getAssetProfileService().findAssetProfileById(tenantId, assetProfileId);
if (assetProfileById == null) {
created = true;
assetProfile.setId(null);
@ -48,7 +53,7 @@ public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor {
assetProfile.setDefault(assetProfileById.isDefault());
}
String assetProfileName = assetProfile.getName();
AssetProfile assetProfileByName = assetProfileService.findAssetProfileByName(tenantId, assetProfileName);
AssetProfile assetProfileByName = edgeCtx.getAssetProfileService().findAssetProfileByName(tenantId, assetProfileName);
if (assetProfileByName != null && !assetProfileByName.getId().equals(assetProfileId)) {
assetProfileName = assetProfileName + "_" + StringUtils.randomAlphabetic(15);
log.warn("[{}] Asset profile with name {} already exists. Renaming asset profile name to {}",
@ -66,7 +71,7 @@ public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor {
if (created) {
assetProfile.setId(assetProfileId);
}
assetProfileService.saveAssetProfile(assetProfile, false, true);
edgeCtx.getAssetProfileService().saveAssetProfile(assetProfile, false, true);
} catch (Exception e) {
log.error("[{}] Failed to process asset profile update msg [{}]", tenantId, assetProfileUpdateMsg, e);
throw e;
@ -83,4 +88,5 @@ public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor {
protected abstract void setDefaultEdgeRuleChainId(AssetProfile assetProfile, RuleChainId ruleChainId, AssetProfileUpdateMsg assetProfileUpdateMsg);
protected abstract void setDefaultDashboardId(TenantId tenantId, DashboardId dashboardId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg);
}

23
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/customer/CustomerEdgeProcessor.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc.processor.customer;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EdgeUtils;
@ -37,6 +38,7 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.customer.CustomerMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.customer.CustomerMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
import java.util.ArrayList;
@ -48,32 +50,33 @@ import java.util.UUID;
@TbCoreComponent
public class CustomerEdgeProcessor extends BaseEdgeProcessor {
@Autowired
private CustomerMsgConstructorFactory customerMsgConstructorFactory;
public DownlinkMsg convertCustomerEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
CustomerId customerId = new CustomerId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (CustomerMsgConstructor) customerMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
Customer customer = customerService.findCustomerById(edgeEvent.getTenantId(), customerId);
Customer customer = edgeCtx.getCustomerService().findCustomerById(edgeEvent.getTenantId(), customerId);
if (customer != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
CustomerUpdateMsg customerUpdateMsg = ((CustomerMsgConstructor)
customerMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructCustomerUpdatedMsg(msgType, customer);
downlinkMsg = DownlinkMsg.newBuilder()
CustomerUpdateMsg customerUpdateMsg = msgConstructor.constructCustomerUpdatedMsg(msgType, customer);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addCustomerUpdateMsg(customerUpdateMsg)
.build();
}
}
case DELETED -> {
CustomerUpdateMsg customerUpdateMsg = ((CustomerMsgConstructor)
customerMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructCustomerDeleteMsg(customerId);
downlinkMsg = DownlinkMsg.newBuilder()
CustomerUpdateMsg customerUpdateMsg = msgConstructor.constructCustomerDeleteMsg(customerId);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addCustomerUpdateMsg(customerUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
public ListenableFuture<Void> processCustomerNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
@ -84,7 +87,7 @@ public class CustomerEdgeProcessor extends BaseEdgeProcessor {
switch (actionType) {
case UPDATED:
List<ListenableFuture<Void>> futures = new ArrayList<>();
PageDataIterable<Edge> edges = new PageDataIterable<>(link -> edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, link), 1024);
PageDataIterable<Edge> edges = new PageDataIterable<>(link -> edgeCtx.getEdgeService().findEdgesByTenantIdAndCustomerId(tenantId, customerId, link), 1024);
for (Edge edge : edges) {
futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, customerId, null));
}

14
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java

@ -16,11 +16,13 @@
package org.thingsboard.server.service.edge.rpc.processor.dashboard;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.ShortCustomerInfo;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@ -29,6 +31,9 @@ import java.util.Set;
@Slf4j
public abstract class BaseDashboardProcessor extends BaseEdgeProcessor {
@Autowired
private DataValidator<Dashboard> dashboardValidator;
protected boolean saveOrUpdateDashboard(TenantId tenantId, DashboardId dashboardId, DashboardUpdateMsg dashboardUpdateMsg, CustomerId customerId) {
boolean created = false;
Dashboard dashboard = constructDashboardFromUpdateMsg(tenantId, dashboardId, dashboardUpdateMsg);
@ -36,7 +41,7 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor {
throw new RuntimeException("[{" + tenantId + "}] dashboardUpdateMsg {" + dashboardUpdateMsg + "} cannot be converted to dashboard");
}
Set<ShortCustomerInfo> assignedCustomers = null;
Dashboard dashboardById = dashboardService.findDashboardById(tenantId, dashboardId);
Dashboard dashboardById = edgeCtx.getDashboardService().findDashboardById(tenantId, dashboardId);
if (dashboardById == null) {
created = true;
dashboard.setId(null);
@ -58,11 +63,11 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor {
}
}
dashboard.setAssignedCustomers(assignedCustomers);
Dashboard savedDashboard = dashboardService.saveDashboard(dashboard, false);
Dashboard savedDashboard = edgeCtx.getDashboardService().saveDashboard(dashboard, false);
if (msgAssignedCustomers != null && !msgAssignedCustomers.isEmpty()) {
for (ShortCustomerInfo assignedCustomer : msgAssignedCustomers) {
if (assignedCustomer.getCustomerId().equals(customerId)) {
dashboardService.assignDashboardToCustomer(tenantId, savedDashboard.getId(), assignedCustomer.getCustomerId());
edgeCtx.getDashboardService().assignDashboardToCustomer(tenantId, savedDashboard.getId(), assignedCustomer.getCustomerId());
}
}
} else {
@ -75,7 +80,7 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor {
if (dashboard.getAssignedCustomers() != null && !dashboard.getAssignedCustomers().isEmpty()) {
for (ShortCustomerInfo assignedCustomer : dashboard.getAssignedCustomers()) {
if (assignedCustomer.getCustomerId().equals(customerId)) {
dashboardService.unassignDashboardFromCustomer(tenantId, dashboard.getId(), assignedCustomer.getCustomerId());
edgeCtx.getDashboardService().unassignDashboardFromCustomer(tenantId, dashboard.getId(), assignedCustomer.getCustomerId());
}
}
}
@ -84,4 +89,5 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor {
protected abstract Dashboard constructDashboardFromUpdateMsg(TenantId tenantId, DashboardId dashboardId, DashboardUpdateMsg dashboardUpdateMsg);
protected abstract Set<ShortCustomerInfo> filterNonExistingCustomers(TenantId tenantId, Set<ShortCustomerInfo> assignedCustomers);
}

34
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc.processor.dashboard;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.EdgeUtils;
@ -34,6 +35,7 @@ import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.service.edge.rpc.constructor.dashboard.DashboardMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.dashboard.DashboardMsgConstructorFactory;
import java.util.Set;
import java.util.UUID;
@ -41,6 +43,9 @@ import java.util.UUID;
@Slf4j
public abstract class DashboardEdgeProcessor extends BaseDashboardProcessor implements DashboardProcessor {
@Autowired
private DashboardMsgConstructorFactory dashboardMsgConstructorFactory;
@Override
public ListenableFuture<Void> processDashboardMsgFromEdge(TenantId tenantId, Edge edge, DashboardUpdateMsg dashboardUpdateMsg) {
log.trace("[{}] executing processDashboardMsgFromEdge [{}] from edge [{}]", tenantId, dashboardUpdateMsg, edge.getId());
@ -54,9 +59,9 @@ public abstract class DashboardEdgeProcessor extends BaseDashboardProcessor impl
saveOrUpdateDashboard(tenantId, dashboardId, dashboardUpdateMsg, edge);
return Futures.immediateFuture(null);
case ENTITY_DELETED_RPC_MESSAGE:
Dashboard dashboardToDelete = dashboardService.findDashboardById(tenantId, dashboardId);
Dashboard dashboardToDelete = edgeCtx.getDashboardService().findDashboardById(tenantId, dashboardId);
if (dashboardToDelete != null) {
dashboardService.unassignDashboardFromEdge(tenantId, dashboardId, edge.getId());
edgeCtx.getDashboardService().unassignDashboardFromEdge(tenantId, dashboardId, edge.getId());
}
return Futures.immediateFuture(null);
case UNRECOGNIZED:
@ -76,18 +81,17 @@ public abstract class DashboardEdgeProcessor extends BaseDashboardProcessor impl
}
private void saveOrUpdateDashboard(TenantId tenantId, DashboardId dashboardId, DashboardUpdateMsg dashboardUpdateMsg, Edge edge) {
boolean created = super.saveOrUpdateDashboard(tenantId, dashboardId, dashboardUpdateMsg,
edge.getCustomerId());
boolean created = super.saveOrUpdateDashboard(tenantId, dashboardId, dashboardUpdateMsg, edge.getCustomerId());
if (created) {
createRelationFromEdge(tenantId, edge.getId(), dashboardId);
pushDashboardCreatedEventToRuleEngine(tenantId, edge, dashboardId);
dashboardService.assignDashboardToEdge(tenantId, dashboardId, edge.getId());
edgeCtx.getDashboardService().assignDashboardToEdge(tenantId, dashboardId, edge.getId());
}
}
private void pushDashboardCreatedEventToRuleEngine(TenantId tenantId, Edge edge, DashboardId dashboardId) {
try {
Dashboard dashboard = dashboardService.findDashboardById(tenantId, dashboardId);
Dashboard dashboard = edgeCtx.getDashboardService().findDashboardById(tenantId, dashboardId);
String dashboardAsString = JacksonUtil.toString(dashboard);
TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null);
pushEntityEventToRuleEngine(tenantId, dashboardId, null, TbMsgType.ENTITY_CREATED, dashboardAsString, msgMetaData);
@ -99,26 +103,28 @@ public abstract class DashboardEdgeProcessor extends BaseDashboardProcessor impl
@Override
public DownlinkMsg convertDashboardEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
DashboardId dashboardId = new DashboardId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (DashboardMsgConstructor) dashboardMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED, ASSIGNED_TO_EDGE, ASSIGNED_TO_CUSTOMER, UNASSIGNED_FROM_CUSTOMER -> {
Dashboard dashboard = dashboardService.findDashboardById(edgeEvent.getTenantId(), dashboardId);
Dashboard dashboard = edgeCtx.getDashboardService().findDashboardById(edgeEvent.getTenantId(), dashboardId);
if (dashboard != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
DashboardUpdateMsg dashboardUpdateMsg = msgConstructor.constructDashboardUpdatedMsg(msgType, dashboard);
downlinkMsg = DownlinkMsg.newBuilder()
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addDashboardUpdateMsg(dashboardUpdateMsg)
.build();
}
}
case DELETED, UNASSIGNED_FROM_EDGE -> downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addDashboardUpdateMsg(msgConstructor.constructDashboardDeleteMsg(dashboardId))
.build();
case DELETED, UNASSIGNED_FROM_EDGE -> {
DashboardUpdateMsg dashboardUpdateMsg = msgConstructor.constructDashboardDeleteMsg(dashboardId);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addDashboardUpdateMsg(dashboardUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
@Override

1
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessorV2.java

@ -33,4 +33,5 @@ public class DashboardEdgeProcessorV2 extends DashboardEdgeProcessor {
protected Dashboard constructDashboardFromUpdateMsg(TenantId tenantId, DashboardId dashboardId, DashboardUpdateMsg dashboardUpdateMsg) {
return JacksonUtil.fromString(dashboardUpdateMsg.getEntity(), Dashboard.class, true);
}
}

19
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.device;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.StringUtils;
@ -23,6 +24,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.gen.edge.v1.DeviceCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@ -30,6 +32,9 @@ import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
@Autowired
private DataValidator<Device> deviceValidator;
protected Pair<Boolean, Boolean> saveOrUpdateDevice(TenantId tenantId, DeviceId deviceId, DeviceUpdateMsg deviceUpdateMsg) {
boolean created = false;
boolean deviceNameUpdated = false;
@ -39,7 +44,7 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
if (device == null) {
throw new RuntimeException("[{" + tenantId + "}] deviceUpdateMsg {" + deviceUpdateMsg + "} cannot be converted to device");
}
Device deviceById = deviceService.findDeviceById(tenantId, deviceId);
Device deviceById = edgeCtx.getDeviceService().findDeviceById(tenantId, deviceId);
if (deviceById == null) {
created = true;
device.setId(null);
@ -47,7 +52,7 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
device.setId(deviceId);
}
String deviceName = device.getName();
Device deviceByName = deviceService.findDeviceByTenantIdAndName(tenantId, deviceName);
Device deviceByName = edgeCtx.getDeviceService().findDeviceByTenantIdAndName(tenantId, deviceName);
if (deviceByName != null && !deviceByName.getId().equals(deviceId)) {
deviceName = deviceName + "_" + StringUtils.randomAlphabetic(15);
log.warn("[{}] Device with name {} already exists. Renaming device name to {}",
@ -61,8 +66,8 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
if (created) {
device.setId(deviceId);
}
Device savedDevice = deviceService.saveDevice(device, false);
tbClusterService.onDeviceUpdated(savedDevice, created ? null : device);
Device savedDevice = edgeCtx.getDeviceService().saveDevice(device, false);
edgeCtx.getClusterService().onDeviceUpdated(savedDevice, created ? null : device);
} catch (Exception e) {
log.error("[{}] Failed to process device update msg [{}]", tenantId, deviceUpdateMsg, e);
throw e;
@ -77,12 +82,12 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
if (deviceCredentials == null) {
throw new RuntimeException("[{" + tenantId + "}] deviceCredentialsUpdateMsg {" + deviceCredentialsUpdateMsg + "} cannot be converted to device credentials");
}
Device device = deviceService.findDeviceById(tenantId, deviceCredentials.getDeviceId());
Device device = edgeCtx.getDeviceService().findDeviceById(tenantId, deviceCredentials.getDeviceId());
if (device != null) {
log.debug("[{}] Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]",
tenantId, device.getName(), deviceCredentials.getCredentialsId(), deviceCredentials.getCredentialsValue());
try {
DeviceCredentials deviceCredentialsByDeviceId = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, device.getId());
DeviceCredentials deviceCredentialsByDeviceId = edgeCtx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(tenantId, device.getId());
if (deviceCredentialsByDeviceId == null) {
deviceCredentialsByDeviceId = new DeviceCredentials();
deviceCredentialsByDeviceId.setDeviceId(device.getId());
@ -90,7 +95,7 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
deviceCredentialsByDeviceId.setCredentialsType(deviceCredentials.getCredentialsType());
deviceCredentialsByDeviceId.setCredentialsId(deviceCredentials.getCredentialsId());
deviceCredentialsByDeviceId.setCredentialsValue(deviceCredentials.getCredentialsValue());
deviceCredentialsService.updateDeviceCredentials(tenantId, deviceCredentialsByDeviceId);
edgeCtx.getDeviceCredentialsService().updateDeviceCredentials(tenantId, deviceCredentialsByDeviceId);
} catch (Exception e) {
log.error("[{}] Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]",

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

@ -71,9 +71,9 @@ public abstract class DeviceEdgeProcessor extends BaseDeviceProcessor implements
saveOrUpdateDevice(tenantId, deviceId, deviceUpdateMsg, edge);
return Futures.immediateFuture(null);
case ENTITY_DELETED_RPC_MESSAGE:
Device deviceToDelete = deviceService.findDeviceById(tenantId, deviceId);
Device deviceToDelete = edgeCtx.getDeviceService().findDeviceById(tenantId, deviceId);
if (deviceToDelete != null) {
deviceService.unassignDeviceFromEdge(tenantId, deviceId, edge.getId());
edgeCtx.getDeviceService().unassignDeviceFromEdge(tenantId, deviceId, edge.getId());
}
return Futures.immediateFuture(null);
case UNRECOGNIZED:
@ -111,7 +111,7 @@ public abstract class DeviceEdgeProcessor extends BaseDeviceProcessor implements
if (created) {
createRelationFromEdge(tenantId, edge.getId(), deviceId);
pushDeviceCreatedEventToRuleEngine(tenantId, edge, deviceId);
deviceService.assignDeviceToEdge(tenantId, deviceId, edge.getId());
edgeCtx.getDeviceService().assignDeviceToEdge(tenantId, deviceId, edge.getId());
}
Boolean deviceNameUpdated = resultPair.getSecond();
if (deviceNameUpdated) {
@ -121,7 +121,7 @@ public abstract class DeviceEdgeProcessor extends BaseDeviceProcessor implements
private void pushDeviceCreatedEventToRuleEngine(TenantId tenantId, Edge edge, DeviceId deviceId) {
try {
Device device = deviceService.findDeviceById(tenantId, deviceId);
Device device = edgeCtx.getDeviceService().findDeviceById(tenantId, deviceId);
String deviceAsString = JacksonUtil.toString(device);
TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, device.getCustomerId());
pushEntityEventToRuleEngine(tenantId, deviceId, device.getCustomerId(), TbMsgType.ENTITY_CREATED, deviceAsString, msgMetaData);
@ -168,7 +168,7 @@ public abstract class DeviceEdgeProcessor extends BaseDeviceProcessor implements
new FromDeviceRpcResponseActorMsg(deviceRpcCallMsg.getRequestId(),
tenantId,
deviceId, response);
tbClusterService.pushMsgToCore(msg, callback);
edgeCtx.getClusterService().pushMsgToCore(msg, callback);
return futureToSet;
}
@ -181,7 +181,7 @@ public abstract class DeviceEdgeProcessor extends BaseDeviceProcessor implements
metaData.putValue("serviceId", deviceRpcCallMsg.getServiceId());
metaData.putValue("sessionId", deviceRpcCallMsg.getSessionId());
metaData.putValue(DataConstants.EDGE_ID, edge.getId().toString());
Device device = deviceService.findDeviceById(tenantId, deviceId);
Device device = edgeCtx.getDeviceService().findDeviceById(tenantId, deviceId);
if (device != null) {
metaData.putValue("deviceName", device.getName());
metaData.putValue("deviceType", device.getType());
@ -192,7 +192,7 @@ public abstract class DeviceEdgeProcessor extends BaseDeviceProcessor implements
data.put("params", deviceRpcCallMsg.getRequestMsg().getParams());
TbMsg tbMsg = TbMsg.newMsg(TbMsgType.TO_SERVER_RPC_REQUEST, deviceId, null, metaData,
TbMsgDataType.JSON, JacksonUtil.toString(data));
tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() {
edgeCtx.getClusterService().pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
log.debug("[{}] Successfully send TO_SERVER_RPC_REQUEST to rule engine [{}], deviceRpcCallMsg {}",
@ -213,47 +213,44 @@ public abstract class DeviceEdgeProcessor extends BaseDeviceProcessor implements
}
@Override
public DownlinkMsg convertDeviceEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion) {
public DownlinkMsg convertDeviceEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
DeviceId deviceId = new DeviceId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (DeviceMsgConstructor) deviceMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
var msgConstructor = (DeviceMsgConstructor) edgeCtx.getDeviceMsgConstructorFactory().getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED:
case UPDATED:
case ASSIGNED_TO_EDGE:
case ASSIGNED_TO_CUSTOMER:
case UNASSIGNED_FROM_CUSTOMER:
Device device = deviceService.findDeviceById(edgeEvent.getTenantId(), deviceId);
Device device = edgeCtx.getDeviceService().findDeviceById(edgeEvent.getTenantId(), deviceId);
if (device != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
DeviceUpdateMsg deviceUpdateMsg = msgConstructor.constructDeviceUpdatedMsg(msgType, device);
DownlinkMsg.Builder builder = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addDeviceUpdateMsg(deviceUpdateMsg);
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(edgeEvent.getTenantId(), deviceId);
DeviceCredentials deviceCredentials = edgeCtx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(edgeEvent.getTenantId(), deviceId);
if (deviceCredentials != null) {
DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg = msgConstructor.constructDeviceCredentialsUpdatedMsg(deviceCredentials);
builder.addDeviceCredentialsUpdateMsg(deviceCredentialsUpdateMsg).build();
}
if (UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE.equals(msgType)) {
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(edgeEvent.getTenantId(), device.getDeviceProfileId());
deviceProfile = checkIfDeviceProfileDefaultFieldsAssignedToEdge(edgeEvent.getTenantId(), edgeId, deviceProfile, edgeVersion);
DeviceProfile deviceProfile = edgeCtx.getDeviceProfileService().findDeviceProfileById(edgeEvent.getTenantId(), device.getDeviceProfileId());
builder.addDeviceProfileUpdateMsg(msgConstructor.constructDeviceProfileUpdatedMsg(msgType, deviceProfile));
}
downlinkMsg = builder.build();
return builder.build();
}
break;
case DELETED:
case UNASSIGNED_FROM_EDGE:
downlinkMsg = DownlinkMsg.newBuilder()
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addDeviceUpdateMsg(msgConstructor.constructDeviceDeleteMsg(deviceId))
.build();
break;
case CREDENTIALS_UPDATED:
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(edgeEvent.getTenantId(), deviceId);
DeviceCredentials deviceCredentials = edgeCtx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(edgeEvent.getTenantId(), deviceId);
if (deviceCredentials != null) {
downlinkMsg = DownlinkMsg.newBuilder()
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addDeviceCredentialsUpdateMsg(msgConstructor.constructDeviceCredentialsUpdatedMsg(deviceCredentials))
.build();
@ -265,7 +262,7 @@ public abstract class DeviceEdgeProcessor extends BaseDeviceProcessor implements
.addDeviceRpcCallMsg(msgConstructor.constructDeviceRpcCallMsg(edgeEvent.getEntityId(), edgeEvent.getBody()))
.build();
}
return downlinkMsg;
return null;
}
}

2
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProcessor.java

@ -33,7 +33,7 @@ public interface DeviceProcessor extends EdgeProcessor {
ListenableFuture<Void> processDeviceCredentialsMsgFromEdge(TenantId tenantId, EdgeId edgeId, DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg);
DownlinkMsg convertDeviceEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion);
DownlinkMsg convertDeviceEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion);
ListenableFuture<Void> processDeviceRpcCallFromEdge(TenantId tenantId, Edge edge, DeviceRpcCallMsg deviceRpcCallMsg);

12
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/profile/BaseDeviceProfileProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.device.profile;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.StringUtils;
@ -23,12 +24,16 @@ import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor {
@Autowired
private DataValidator<DeviceProfile> deviceProfileValidator;
protected Pair<Boolean, Boolean> saveOrUpdateDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId, DeviceProfileUpdateMsg deviceProfileUpdateMsg) {
boolean created = false;
boolean deviceProfileNameUpdated = false;
@ -38,7 +43,7 @@ public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor {
if (deviceProfile == null) {
throw new RuntimeException("[{" + tenantId + "}] deviceProfileUpdateMsg {" + deviceProfileUpdateMsg + "} cannot be converted to device profile");
}
DeviceProfile deviceProfileById = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
DeviceProfile deviceProfileById = edgeCtx.getDeviceProfileService().findDeviceProfileById(tenantId, deviceProfileId);
if (deviceProfileById == null) {
created = true;
deviceProfile.setId(null);
@ -48,7 +53,7 @@ public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor {
deviceProfile.setDefault(deviceProfileById.isDefault());
}
String deviceProfileName = deviceProfile.getName();
DeviceProfile deviceProfileByName = deviceProfileService.findDeviceProfileByName(tenantId, deviceProfileName);
DeviceProfile deviceProfileByName = edgeCtx.getDeviceProfileService().findDeviceProfileByName(tenantId, deviceProfileName);
if (deviceProfileByName != null && !deviceProfileByName.getId().equals(deviceProfileId)) {
deviceProfileName = deviceProfileName + "_" + StringUtils.randomAlphabetic(15);
log.warn("[{}] Device profile with name {} already exists. Renaming device profile name to {}",
@ -66,7 +71,7 @@ public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor {
if (created) {
deviceProfile.setId(deviceProfileId);
}
deviceProfileService.saveDeviceProfile(deviceProfile, false, true);
edgeCtx.getDeviceProfileService().saveDeviceProfile(deviceProfile, false, true);
} catch (Exception e) {
log.error("[{}] Failed to process device profile update msg [{}]", tenantId, deviceProfileUpdateMsg, e);
throw e;
@ -83,4 +88,5 @@ public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor {
protected abstract void setDefaultEdgeRuleChainId(DeviceProfile deviceProfile, RuleChainId ruleChainId, DeviceProfileUpdateMsg deviceProfileUpdateMsg);
protected abstract void setDefaultDashboardId(TenantId tenantId, DashboardId dashboardId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg);
}

17
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/profile/DeviceProfileEdgeProcessor.java

@ -27,7 +27,6 @@ import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -83,7 +82,7 @@ public abstract class DeviceProfileEdgeProcessor extends BaseDeviceProfileProces
private void pushDeviceProfileCreatedEventToRuleEngine(TenantId tenantId, Edge edge, DeviceProfileId deviceProfileId) {
try {
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
DeviceProfile deviceProfile = edgeCtx.getDeviceProfileService().findDeviceProfileById(tenantId, deviceProfileId);
String deviceProfileAsString = JacksonUtil.toString(deviceProfile);
TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null);
pushEntityEventToRuleEngine(tenantId, deviceProfileId, null, TbMsgType.ENTITY_CREATED, deviceProfileAsString, msgMetaData);
@ -93,18 +92,16 @@ public abstract class DeviceProfileEdgeProcessor extends BaseDeviceProfileProces
}
@Override
public DownlinkMsg convertDeviceProfileEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion) {
public DownlinkMsg convertDeviceProfileEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
DeviceProfileId deviceProfileId = new DeviceProfileId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (DeviceMsgConstructor) deviceMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
var msgConstructor = (DeviceMsgConstructor) edgeCtx.getDeviceMsgConstructorFactory().getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(edgeEvent.getTenantId(), deviceProfileId);
DeviceProfile deviceProfile = edgeCtx.getDeviceProfileService().findDeviceProfileById(edgeEvent.getTenantId(), deviceProfileId);
if (deviceProfile != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
deviceProfile = checkIfDeviceProfileDefaultFieldsAssignedToEdge(edgeEvent.getTenantId(), edgeId, deviceProfile, edgeVersion);
DeviceProfileUpdateMsg deviceProfileUpdateMsg = msgConstructor.constructDeviceProfileUpdatedMsg(msgType, deviceProfile);
downlinkMsg = DownlinkMsg.newBuilder()
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addDeviceProfileUpdateMsg(deviceProfileUpdateMsg)
.build();
@ -112,13 +109,13 @@ public abstract class DeviceProfileEdgeProcessor extends BaseDeviceProfileProces
}
case DELETED -> {
DeviceProfileUpdateMsg deviceProfileUpdateMsg = msgConstructor.constructDeviceProfileDeleteMsg(deviceProfileId);
downlinkMsg = DownlinkMsg.newBuilder()
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addDeviceProfileUpdateMsg(deviceProfileUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/profile/DeviceProfileProcessor.java

@ -18,7 +18,6 @@ package org.thingsboard.server.service.edge.rpc.processor.device.profile;
import com.google.common.util.concurrent.ListenableFuture;
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.TenantId;
import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
@ -29,5 +28,6 @@ public interface DeviceProfileProcessor extends EdgeProcessor {
ListenableFuture<Void> processDeviceProfileMsgFromEdge(TenantId tenantId, Edge edge, DeviceProfileUpdateMsg deviceProfileUpdateMsg);
DownlinkMsg convertDeviceProfileEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion);
DownlinkMsg convertDeviceProfileEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion);
}

22
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/edge/EdgeProcessor.java

@ -48,21 +48,19 @@ public class EdgeProcessor extends BaseEdgeProcessor {
public DownlinkMsg convertEdgeEventToDownlink(EdgeEvent edgeEvent) {
EdgeId edgeId = new EdgeId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
switch (edgeEvent.getAction()) {
case ASSIGNED_TO_CUSTOMER, UNASSIGNED_FROM_CUSTOMER -> {
Edge edge = edgeService.findEdgeById(edgeEvent.getTenantId(), edgeId);
Edge edge = edgeCtx.getEdgeService().findEdgeById(edgeEvent.getTenantId(), edgeId);
if (edge != null) {
EdgeConfiguration edgeConfigMsg =
edgeMsgConstructor.constructEdgeConfiguration(edge);
downlinkMsg = DownlinkMsg.newBuilder()
EdgeConfiguration edgeConfigMsg = edgeCtx.getEdgeMsgConstructor().constructEdgeConfiguration(edge);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.setEdgeConfiguration(edgeConfigMsg)
.build();
}
}
}
return downlinkMsg;
return null;
}
public ListenableFuture<Void> processEdgeNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
@ -70,9 +68,9 @@ public class EdgeProcessor extends BaseEdgeProcessor {
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
switch (actionType) {
case ASSIGNED_TO_CUSTOMER:
case ASSIGNED_TO_CUSTOMER: {
CustomerId customerId = JacksonUtil.fromString(edgeNotificationMsg.getBody(), CustomerId.class);
Edge edge = edgeService.findEdgeById(tenantId, edgeId);
Edge edge = edgeCtx.getEdgeService().findEdgeById(tenantId, edgeId);
if (customerId != null && (edge == null || customerId.isNullUid())) {
return Futures.immediateFuture(null);
}
@ -82,7 +80,7 @@ public class EdgeProcessor extends BaseEdgeProcessor {
PageLink pageLink = new PageLink(1000);
PageData<User> pageData;
do {
pageData = userService.findCustomerUsers(tenantId, customerId, pageLink);
pageData = edgeCtx.getUserService().findCustomerUsers(tenantId, customerId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}][{}][{}] user(s) are going to be added to edge.", tenantId, edge.getId(), pageData.getData().size());
for (User user : pageData.getData()) {
@ -94,15 +92,17 @@ public class EdgeProcessor extends BaseEdgeProcessor {
}
} while (pageData != null && pageData.hasNext());
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
case UNASSIGNED_FROM_CUSTOMER:
}
case UNASSIGNED_FROM_CUSTOMER: {
CustomerId customerIdToDelete = JacksonUtil.fromString(edgeNotificationMsg.getBody(), CustomerId.class);
edge = edgeService.findEdgeById(tenantId, edgeId);
Edge edge = edgeCtx.getEdgeService().findEdgeById(tenantId, edgeId);
if (customerIdToDelete != null && (edge == null || customerIdToDelete.isNullUid())) {
return Futures.immediateFuture(null);
}
return Futures.transformAsync(saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.EDGE, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, edgeId, null),
voids -> saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.DELETED, customerIdToDelete, null),
dbCallbackExecutorService);
}
default:
return Futures.immediateFuture(null);
}

11
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/BaseEntityViewProcessor.java

@ -16,18 +16,23 @@
package org.thingsboard.server.service.edge.rpc.processor.entityview;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
public abstract class BaseEntityViewProcessor extends BaseEdgeProcessor {
@Autowired
private DataValidator<EntityView> entityViewValidator;
protected Pair<Boolean, Boolean> saveOrUpdateEntityView(TenantId tenantId, EntityViewId entityViewId, EntityViewUpdateMsg entityViewUpdateMsg) {
boolean created = false;
boolean entityViewNameUpdated = false;
@ -35,7 +40,7 @@ public abstract class BaseEntityViewProcessor extends BaseEdgeProcessor {
if (entityView == null) {
throw new RuntimeException("[{" + tenantId + "}] entityViewUpdateMsg {" + entityViewUpdateMsg + "} cannot be converted to entity view");
}
EntityView entityViewById = entityViewService.findEntityViewById(tenantId, entityViewId);
EntityView entityViewById = edgeCtx.getEntityViewService().findEntityViewById(tenantId, entityViewId);
if (entityViewById == null) {
created = true;
entityView.setId(null);
@ -43,7 +48,7 @@ public abstract class BaseEntityViewProcessor extends BaseEdgeProcessor {
entityView.setId(entityViewId);
}
String entityViewName = entityView.getName();
EntityView entityViewByName = entityViewService.findEntityViewByTenantIdAndName(tenantId, entityViewName);
EntityView entityViewByName = edgeCtx.getEntityViewService().findEntityViewByTenantIdAndName(tenantId, entityViewName);
if (entityViewByName != null && !entityViewByName.getId().equals(entityViewId)) {
entityViewName = entityViewName + "_" + StringUtils.randomAlphanumeric(15);
log.warn("[{}] Entity view with name {} already exists. Renaming entity view name to {}",
@ -57,7 +62,7 @@ public abstract class BaseEntityViewProcessor extends BaseEdgeProcessor {
if (created) {
entityView.setId(entityViewId);
}
entityViewService.saveEntityView(entityView, false);
edgeCtx.getEntityViewService().saveEntityView(entityView, false);
return Pair.of(created, entityViewNameUpdated);
}

31
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc.processor.entityview;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EdgeUtils;
@ -36,12 +37,16 @@ import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorFactory;
import java.util.UUID;
@Slf4j
public abstract class EntityViewEdgeProcessor extends BaseEntityViewProcessor implements EntityViewProcessor {
@Autowired
private EntityViewMsgConstructorFactory entityViewMsgConstructorFactory;
@Override
public ListenableFuture<Void> processEntityViewMsgFromEdge(TenantId tenantId, Edge edge, EntityViewUpdateMsg entityViewUpdateMsg) {
log.trace("[{}] executing processEntityViewMsgFromEdge [{}] from edge [{}]", tenantId, entityViewUpdateMsg, edge.getId());
@ -55,9 +60,9 @@ public abstract class EntityViewEdgeProcessor extends BaseEntityViewProcessor im
saveOrUpdateEntityView(tenantId, entityViewId, entityViewUpdateMsg, edge);
return Futures.immediateFuture(null);
case ENTITY_DELETED_RPC_MESSAGE:
EntityView entityViewToDelete = entityViewService.findEntityViewById(tenantId, entityViewId);
EntityView entityViewToDelete = edgeCtx.getEntityViewService().findEntityViewById(tenantId, entityViewId);
if (entityViewToDelete != null) {
entityViewService.unassignEntityViewFromEdge(tenantId, entityViewId, edge.getId());
edgeCtx.getEntityViewService().unassignEntityViewFromEdge(tenantId, entityViewId, edge.getId());
}
return Futures.immediateFuture(null);
case UNRECOGNIZED:
@ -82,7 +87,7 @@ public abstract class EntityViewEdgeProcessor extends BaseEntityViewProcessor im
if (created) {
createRelationFromEdge(tenantId, edge.getId(), entityViewId);
pushEntityViewCreatedEventToRuleEngine(tenantId, edge, entityViewId);
entityViewService.assignEntityViewToEdge(tenantId, entityViewId, edge.getId());
edgeCtx.getEntityViewService().assignEntityViewToEdge(tenantId, entityViewId, edge.getId());
}
Boolean assetNameUpdated = resultPair.getSecond();
if (assetNameUpdated) {
@ -92,7 +97,7 @@ public abstract class EntityViewEdgeProcessor extends BaseEntityViewProcessor im
private void pushEntityViewCreatedEventToRuleEngine(TenantId tenantId, Edge edge, EntityViewId entityViewId) {
try {
EntityView entityView = entityViewService.findEntityViewById(tenantId, entityViewId);
EntityView entityView = edgeCtx.getEntityViewService().findEntityViewById(tenantId, entityViewId);
String entityViewAsString = JacksonUtil.toString(entityView);
TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, entityView.getCustomerId());
pushEntityEventToRuleEngine(tenantId, entityViewId, entityView.getCustomerId(), TbMsgType.ENTITY_CREATED, entityViewAsString, msgMetaData);
@ -103,26 +108,28 @@ public abstract class EntityViewEdgeProcessor extends BaseEntityViewProcessor im
public DownlinkMsg convertEntityViewEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
EntityViewId entityViewId = new EntityViewId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (EntityViewMsgConstructor) entityViewMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED, ASSIGNED_TO_EDGE, ASSIGNED_TO_CUSTOMER, UNASSIGNED_FROM_CUSTOMER -> {
EntityView entityView = entityViewService.findEntityViewById(edgeEvent.getTenantId(), entityViewId);
EntityView entityView = edgeCtx.getEntityViewService().findEntityViewById(edgeEvent.getTenantId(), entityViewId);
if (entityView != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
EntityViewUpdateMsg entityViewUpdateMsg = msgConstructor.constructEntityViewUpdatedMsg(msgType, entityView);
downlinkMsg = DownlinkMsg.newBuilder()
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addEntityViewUpdateMsg(entityViewUpdateMsg)
.build();
}
}
case DELETED, UNASSIGNED_FROM_EDGE -> downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addEntityViewUpdateMsg(msgConstructor.constructEntityViewDeleteMsg(entityViewId))
.build();
case DELETED, UNASSIGNED_FROM_EDGE -> {
EntityViewUpdateMsg entityViewUpdateMsg = msgConstructor.constructEntityViewDeleteMsg(entityViewId);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addEntityViewUpdateMsg(entityViewUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

17
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/notification/NotificationEdgeProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.notification;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent;
@ -25,12 +26,16 @@ import org.thingsboard.server.common.data.id.NotificationTemplateId;
import org.thingsboard.server.common.data.notification.rule.NotificationRule;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.dao.notification.NotificationRuleService;
import org.thingsboard.server.dao.notification.NotificationTargetService;
import org.thingsboard.server.dao.notification.NotificationTemplateService;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.NotificationRuleUpdateMsg;
import org.thingsboard.server.gen.edge.v1.NotificationTargetUpdateMsg;
import org.thingsboard.server.gen.edge.v1.NotificationTemplateUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.notification.NotificationMsgConstructor;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
@ -38,6 +43,18 @@ import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@TbCoreComponent
public class NotificationEdgeProcessor extends BaseEdgeProcessor {
@Autowired
protected NotificationRuleService notificationRuleService;
@Autowired
private NotificationTargetService notificationTargetService;
@Autowired
private NotificationTemplateService notificationTemplateService;
@Autowired
private NotificationMsgConstructor notificationMsgConstructor;
public DownlinkMsg convertNotificationRuleToDownlink(EdgeEvent edgeEvent) {
NotificationRuleId notificationRuleId = new NotificationRuleId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;

29
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/oauth2/OAuth2EdgeProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.oauth2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.domain.DomainInfo;
@ -23,12 +24,14 @@ import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.DomainId;
import org.thingsboard.server.common.data.id.OAuth2ClientId;
import org.thingsboard.server.common.data.oauth2.OAuth2Client;
import org.thingsboard.server.dao.domain.DomainService;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.OAuth2ClientUpdateMsg;
import org.thingsboard.server.gen.edge.v1.OAuth2DomainUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.oauth2.OAuth2MsgConstructor;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.utils.EdgeVersionUtils;
@ -37,12 +40,17 @@ import org.thingsboard.server.service.edge.rpc.utils.EdgeVersionUtils;
@TbCoreComponent
public class OAuth2EdgeProcessor extends BaseEdgeProcessor {
@Autowired
private DomainService domainService;
@Autowired
private OAuth2MsgConstructor oAuth2MsgConstructor;
public DownlinkMsg convertOAuth2DomainEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
if (EdgeVersionUtils.isEdgeVersionOlderThan(edgeVersion, EdgeVersion.V_3_8_0)) {
return null;
}
DomainId domainId = new DomainId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
@ -54,22 +62,22 @@ public class OAuth2EdgeProcessor extends BaseEdgeProcessor {
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addOAuth2DomainUpdateMsg(oAuth2DomainUpdateMsg);
domainInfo.getOauth2ClientInfos().forEach(clientInfo -> {
OAuth2Client oauth2Client = oAuth2ClientService.findOAuth2ClientById(edgeEvent.getTenantId(), clientInfo.getId());
OAuth2Client oauth2Client = edgeCtx.getOAuth2ClientService().findOAuth2ClientById(edgeEvent.getTenantId(), clientInfo.getId());
OAuth2ClientUpdateMsg oAuth2ClientUpdateMsg = oAuth2MsgConstructor.constructOAuth2ClientUpdateMsg(msgType, oauth2Client);
builder.addOAuth2ClientUpdateMsg(oAuth2ClientUpdateMsg);
});
downlinkMsg = builder.build();
return builder.build();
}
}
case DELETED -> {
OAuth2DomainUpdateMsg oAuth2DomainUpdateMsg = oAuth2MsgConstructor.constructOAuth2DomainDeleteMsg(domainId);
downlinkMsg = DownlinkMsg.newBuilder()
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addOAuth2DomainUpdateMsg(oAuth2DomainUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
public DownlinkMsg convertOAuth2ClientEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
@ -77,19 +85,18 @@ public class OAuth2EdgeProcessor extends BaseEdgeProcessor {
return null;
}
OAuth2ClientId oAuth2ClientId = new OAuth2ClientId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
boolean isPropagateToEdge = oAuth2ClientService.isPropagateOAuth2ClientToEdge(edgeEvent.getTenantId(), oAuth2ClientId);
boolean isPropagateToEdge = edgeCtx.getOAuth2ClientService().isPropagateOAuth2ClientToEdge(edgeEvent.getTenantId(), oAuth2ClientId);
if (!isPropagateToEdge) {
return null;
}
OAuth2Client oAuth2Client = oAuth2ClientService.findOAuth2ClientById(edgeEvent.getTenantId(), oAuth2ClientId);
OAuth2Client oAuth2Client = edgeCtx.getOAuth2ClientService().findOAuth2ClientById(edgeEvent.getTenantId(), oAuth2ClientId);
if (oAuth2Client != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
OAuth2ClientUpdateMsg oAuth2ClientUpdateMsg = oAuth2MsgConstructor.constructOAuth2ClientUpdateMsg(msgType, oAuth2Client);
downlinkMsg = DownlinkMsg.newBuilder()
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addOAuth2ClientUpdateMsg(oAuth2ClientUpdateMsg)
.build();
@ -97,13 +104,13 @@ public class OAuth2EdgeProcessor extends BaseEdgeProcessor {
}
case DELETED -> {
OAuth2ClientUpdateMsg oAuth2ClientDeleteMsg = oAuth2MsgConstructor.constructOAuth2ClientDeleteMsg(oAuth2ClientId);
downlinkMsg = DownlinkMsg.newBuilder()
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addOAuth2ClientUpdateMsg(oAuth2ClientDeleteMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

21
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/ota/OtaPackageEdgeProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.ota;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.OtaPackage;
@ -27,6 +28,7 @@ import org.thingsboard.server.gen.edge.v1.OtaPackageUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Component
@ -34,32 +36,33 @@ import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@TbCoreComponent
public class OtaPackageEdgeProcessor extends BaseEdgeProcessor {
@Autowired
private OtaPackageMsgConstructorFactory otaPackageMsgConstructorFactory;
public DownlinkMsg convertOtaPackageEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
OtaPackageId otaPackageId = new OtaPackageId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (OtaPackageMsgConstructor) otaPackageMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
OtaPackage otaPackage = otaPackageService.findOtaPackageById(edgeEvent.getTenantId(), otaPackageId);
OtaPackage otaPackage = edgeCtx.getOtaPackageService().findOtaPackageById(edgeEvent.getTenantId(), otaPackageId);
if (otaPackage != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
OtaPackageUpdateMsg otaPackageUpdateMsg = ((OtaPackageMsgConstructor)
otaPackageMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructOtaPackageUpdatedMsg(msgType, otaPackage);
downlinkMsg = DownlinkMsg.newBuilder()
OtaPackageUpdateMsg otaPackageUpdateMsg = msgConstructor.constructOtaPackageUpdatedMsg(msgType, otaPackage);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addOtaPackageUpdateMsg(otaPackageUpdateMsg)
.build();
}
}
case DELETED -> {
OtaPackageUpdateMsg otaPackageUpdateMsg = ((OtaPackageMsgConstructor)
otaPackageMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructOtaPackageDeleteMsg(otaPackageId);
downlinkMsg = DownlinkMsg.newBuilder()
OtaPackageUpdateMsg otaPackageUpdateMsg = msgConstructor.constructOtaPackageDeleteMsg(otaPackageId);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addOtaPackageUpdateMsg(otaPackageUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

21
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/queue/QueueEdgeProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.queue;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent;
@ -27,6 +28,7 @@ import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.queue.QueueMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.queue.QueueMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
@ -34,32 +36,33 @@ import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@TbCoreComponent
public class QueueEdgeProcessor extends BaseEdgeProcessor {
@Autowired
private QueueMsgConstructorFactory queueMsgConstructorFactory;
public DownlinkMsg convertQueueEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
QueueId queueId = new QueueId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (QueueMsgConstructor) queueMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
Queue queue = queueService.findQueueById(edgeEvent.getTenantId(), queueId);
Queue queue = edgeCtx.getQueueService().findQueueById(edgeEvent.getTenantId(), queueId);
if (queue != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
QueueUpdateMsg queueUpdateMsg = ((QueueMsgConstructor)
queueMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructQueueUpdatedMsg(msgType, queue);
downlinkMsg = DownlinkMsg.newBuilder()
QueueUpdateMsg queueUpdateMsg = msgConstructor.constructQueueUpdatedMsg(msgType, queue);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addQueueUpdateMsg(queueUpdateMsg)
.build();
}
}
case DELETED -> {
QueueUpdateMsg queueDeleteMsg = ((QueueMsgConstructor)
queueMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructQueueDeleteMsg(queueId);
downlinkMsg = DownlinkMsg.newBuilder()
QueueUpdateMsg queueDeleteMsg = msgConstructor.constructQueueDeleteMsg(queueId);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addQueueUpdateMsg(queueDeleteMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

7
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java

@ -36,15 +36,14 @@ public abstract class BaseRelationProcessor extends BaseEdgeProcessor {
switch (relationUpdateMsg.getMsgType()) {
case ENTITY_CREATED_RPC_MESSAGE:
case ENTITY_UPDATED_RPC_MESSAGE:
if (isEntityExists(tenantId, entityRelation.getTo())
&& isEntityExists(tenantId, entityRelation.getFrom())) {
relationService.saveRelation(tenantId, entityRelation);
if (isEntityExists(tenantId, entityRelation.getTo()) && isEntityExists(tenantId, entityRelation.getFrom())) {
edgeCtx.getRelationService().saveRelation(tenantId, entityRelation);
} else {
log.warn("[{}] Skipping relating update msg because from/to entity doesn't exists on edge, {}", tenantId, relationUpdateMsg);
}
break;
case ENTITY_DELETED_RPC_MESSAGE:
relationService.deleteRelation(tenantId, entityRelation);
edgeCtx.getRelationService().deleteRelation(tenantId, entityRelation);
break;
case UNRECOGNIZED:
default:

9
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/RelationEdgeProcessor.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc.processor.relation;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType;
@ -34,6 +35,7 @@ import org.thingsboard.server.gen.edge.v1.RelationUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.service.edge.rpc.constructor.relation.RelationMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.relation.RelationMsgConstructorFactory;
import java.util.ArrayList;
import java.util.HashSet;
@ -43,6 +45,9 @@ import java.util.Set;
@Slf4j
public abstract class RelationEdgeProcessor extends BaseRelationProcessor implements RelationProcessor {
@Autowired
private RelationMsgConstructorFactory relationMsgConstructorFactory;
@Override
public ListenableFuture<Void> processRelationMsgFromEdge(TenantId tenantId, Edge edge, RelationUpdateMsg relationUpdateMsg) {
log.trace("[{}] executing processRelationMsgFromEdge [{}] from edge [{}]", tenantId, relationUpdateMsg, edge.getId());
@ -74,8 +79,8 @@ public abstract class RelationEdgeProcessor extends BaseRelationProcessor implem
EdgeId originatorEdgeId = safeGetEdgeId(edgeNotificationMsg.getOriginatorEdgeIdMSB(), edgeNotificationMsg.getOriginatorEdgeIdLSB());
Set<EdgeId> uniqueEdgeIds = new HashSet<>();
uniqueEdgeIds.addAll(edgeService.findAllRelatedEdgeIds(tenantId, relation.getTo()));
uniqueEdgeIds.addAll(edgeService.findAllRelatedEdgeIds(tenantId, relation.getFrom()));
uniqueEdgeIds.addAll(edgeCtx.getEdgeService().findAllRelatedEdgeIds(tenantId, relation.getTo()));
uniqueEdgeIds.addAll(edgeCtx.getEdgeService().findAllRelatedEdgeIds(tenantId, relation.getFrom()));
uniqueEdgeIds.remove(originatorEdgeId);
if (uniqueEdgeIds.isEmpty()) {
return Futures.immediateFuture(null);

11
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/BaseResourceProcessor.java

@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.processor.resource;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.TbResource;
@ -24,12 +25,16 @@ import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.gen.edge.v1.ResourceUpdateMsg;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
public abstract class BaseResourceProcessor extends BaseEdgeProcessor {
@Autowired
private DataValidator<TbResource> resourceValidator;
protected boolean saveOrUpdateTbResource(TenantId tenantId, TbResourceId tbResourceId, ResourceUpdateMsg resourceUpdateMsg) {
boolean resourceKeyUpdated = false;
try {
@ -38,7 +43,7 @@ public abstract class BaseResourceProcessor extends BaseEdgeProcessor {
throw new RuntimeException("[{" + tenantId + "}] resourceUpdateMsg {" + resourceUpdateMsg + " } cannot be converted to resource");
}
boolean created = false;
TbResource resourceById = resourceService.findResourceById(tenantId, tbResourceId);
TbResource resourceById = edgeCtx.getResourceService().findResourceById(tenantId, tbResourceId);
if (resourceById == null) {
resource.setCreatedTime(Uuids.unixTimestamp(tbResourceId.getId()));
created = true;
@ -49,7 +54,7 @@ public abstract class BaseResourceProcessor extends BaseEdgeProcessor {
String resourceKey = resource.getResourceKey();
ResourceType resourceType = resource.getResourceType();
PageDataIterable<TbResource> resourcesIterable = new PageDataIterable<>(
link -> resourceService.findTenantResourcesByResourceTypeAndPageLink(tenantId, resourceType, link), 1024);
link -> edgeCtx.getResourceService().findTenantResourcesByResourceTypeAndPageLink(tenantId, resourceType, link), 1024);
for (TbResource tbResource : resourcesIterable) {
if (tbResource.getResourceKey().equals(resourceKey) && !tbResourceId.equals(tbResource.getId())) {
resourceKey = StringUtils.randomAlphabetic(15) + "_" + resourceKey;
@ -63,7 +68,7 @@ public abstract class BaseResourceProcessor extends BaseEdgeProcessor {
if (created) {
resource.setId(tbResourceId);
}
resourceService.saveResource(resource, false);
edgeCtx.getResourceService().saveResource(resource, false);
} catch (Exception e) {
log.error("[{}] Failed to process resource update msg [{}]", tenantId, resourceUpdateMsg, e);
throw e;

21
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessor.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc.processor.resource;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.edge.Edge;
@ -32,12 +33,16 @@ import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.ResourceUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.service.edge.rpc.constructor.resource.ResourceMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.resource.ResourceMsgConstructorFactory;
import java.util.UUID;
@Slf4j
public abstract class ResourceEdgeProcessor extends BaseResourceProcessor implements ResourceProcessor {
@Autowired
private ResourceMsgConstructorFactory resourceMsgConstructorFactory;
@Override
public ListenableFuture<Void> processResourceMsgFromEdge(TenantId tenantId, Edge edge, ResourceUpdateMsg resourceUpdateMsg) {
TbResourceId tbResourceId = new TbResourceId(new UUID(resourceUpdateMsg.getIdMSB(), resourceUpdateMsg.getIdLSB()));
@ -72,30 +77,28 @@ public abstract class ResourceEdgeProcessor extends BaseResourceProcessor implem
@Override
public DownlinkMsg convertResourceEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
TbResourceId tbResourceId = new TbResourceId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (ResourceMsgConstructor) resourceMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
TbResource tbResource = resourceService.findResourceById(edgeEvent.getTenantId(), tbResourceId);
TbResource tbResource = edgeCtx.getResourceService().findResourceById(edgeEvent.getTenantId(), tbResourceId);
if (tbResource != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
ResourceUpdateMsg resourceUpdateMsg = ((ResourceMsgConstructor)
resourceMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructResourceUpdatedMsg(msgType, tbResource);
downlinkMsg = resourceUpdateMsg != null ? DownlinkMsg.newBuilder()
ResourceUpdateMsg resourceUpdateMsg = msgConstructor.constructResourceUpdatedMsg(msgType, tbResource);
return resourceUpdateMsg != null ? DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addResourceUpdateMsg(resourceUpdateMsg)
.build() : null;
}
}
case DELETED -> {
ResourceUpdateMsg resourceUpdateMsg = ((ResourceMsgConstructor)
resourceMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructResourceDeleteMsg(tbResourceId);
downlinkMsg = DownlinkMsg.newBuilder()
ResourceUpdateMsg resourceUpdateMsg = msgConstructor.constructResourceDeleteMsg(tbResourceId);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addResourceUpdateMsg(resourceUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

23
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/rule/RuleChainEdgeProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.rule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge;
@ -30,6 +31,7 @@ import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.rule.RuleChainMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.rule.RuleChainMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
import static org.thingsboard.server.dao.edge.EdgeServiceImpl.EDGE_IS_ROOT_BODY_KEY;
@ -39,13 +41,16 @@ import static org.thingsboard.server.dao.edge.EdgeServiceImpl.EDGE_IS_ROOT_BODY_
@TbCoreComponent
public class RuleChainEdgeProcessor extends BaseEdgeProcessor {
@Autowired
private RuleChainMsgConstructorFactory ruleChainMsgConstructorFactory;
public DownlinkMsg convertRuleChainEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (RuleChainMsgConstructor) ruleChainMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED, ASSIGNED_TO_EDGE -> {
RuleChain ruleChain = ruleChainService.findRuleChainById(edgeEvent.getTenantId(), ruleChainId);
RuleChain ruleChain = edgeCtx.getRuleChainService().findRuleChainById(edgeEvent.getTenantId(), ruleChainId);
if (ruleChain != null) {
boolean isRoot = false;
if (edgeEvent.getBody() != null && edgeEvent.getBody().get(EDGE_IS_ROOT_BODY_KEY) != null) {
@ -55,7 +60,7 @@ public class RuleChainEdgeProcessor extends BaseEdgeProcessor {
}
}
if (!isRoot) {
Edge edge = edgeService.findEdgeById(edgeEvent.getTenantId(), edgeEvent.getEdgeId());
Edge edge = edgeCtx.getEdgeService().findEdgeById(edgeEvent.getTenantId(), edgeEvent.getEdgeId());
isRoot = edge.getRootRuleChainId().equals(ruleChainId);
}
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
@ -65,9 +70,8 @@ public class RuleChainEdgeProcessor extends BaseEdgeProcessor {
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addRuleChainUpdateMsg(ruleChainUpdateMsg);
RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId);
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = ((RuleChainMsgConstructor)
ruleChainMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion))
RuleChainMetaData ruleChainMetaData = edgeCtx.getRuleChainService().loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId);
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = msgConstructor
.constructRuleChainMetadataUpdatedMsg(edgeEvent.getTenantId(), msgType, ruleChainMetaData, edgeVersion);
if (ruleChainMetadataUpdateMsg != null) {
builder.addRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg);
@ -85,22 +89,21 @@ public class RuleChainEdgeProcessor extends BaseEdgeProcessor {
public DownlinkMsg convertRuleChainMetadataEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId());
RuleChain ruleChain = ruleChainService.findRuleChainById(edgeEvent.getTenantId(), ruleChainId);
DownlinkMsg downlinkMsg = null;
RuleChain ruleChain = edgeCtx.getRuleChainService().findRuleChainById(edgeEvent.getTenantId(), ruleChainId);
var msgConstructor = (RuleChainMsgConstructor) ruleChainMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
if (ruleChain != null) {
RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId);
RuleChainMetaData ruleChainMetaData = edgeCtx.getRuleChainService().loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId);
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = msgConstructor
.constructRuleChainMetadataUpdatedMsg(edgeEvent.getTenantId(), msgType, ruleChainMetaData, edgeVersion);
if (ruleChainMetadataUpdateMsg != null) {
downlinkMsg = DownlinkMsg.newBuilder()
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

5
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/settings/AdminSettingsEdgeProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.settings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.AdminSettings;
@ -26,6 +27,7 @@ import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.settings.AdminSettingsMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.settings.AdminSettingsMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
@ -33,6 +35,9 @@ import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@TbCoreComponent
public class AdminSettingsEdgeProcessor extends BaseEdgeProcessor {
@Autowired
private AdminSettingsMsgConstructorFactory adminSettingsMsgConstructorFactory;
public DownlinkMsg convertAdminSettingsEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
AdminSettings adminSettings = JacksonUtil.convertValue(edgeEvent.getBody(), AdminSettings.class);
if (adminSettings == null) {

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

@ -28,6 +28,8 @@ import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.adaptor.JsonConverter;
import org.thingsboard.server.common.data.AttributeScope;
@ -66,7 +68,13 @@ import org.thingsboard.server.queue.TbQueueCallback;
import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.TbQueueProducer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.service.edge.rpc.constructor.telemetry.EntityDataMsgConstructor;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
import org.thingsboard.server.service.profile.TbAssetProfileCache;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import java.util.ArrayList;
import java.util.List;
@ -75,6 +83,25 @@ import java.util.UUID;
@Slf4j
public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
@Autowired
private EntityDataMsgConstructor entityDataMsgConstructor;
@Autowired
private PartitionService partitionService;
@Autowired
private TelemetrySubscriptionService tsSubService;
@Autowired
private TbDeviceProfileCache deviceProfileCache;
@Autowired
private TbAssetProfileCache assetProfileCache;
@Lazy
@Autowired
private TbQueueProducerProvider producerProvider;
private final Gson gson = new Gson();
private TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreMsg>> tbCoreMsgProducer;
@ -139,7 +166,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
CustomerId customerId = null;
switch (entityId.getEntityType()) {
case DEVICE -> {
Device device = deviceService.findDeviceById(tenantId, new DeviceId(entityId.getId()));
Device device = edgeCtx.getDeviceService().findDeviceById(tenantId, new DeviceId(entityId.getId()));
if (device != null) {
customerId = device.getCustomerId();
metaData.putValue("deviceName", device.getName());
@ -147,7 +174,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
}
}
case ASSET -> {
Asset asset = assetService.findAssetById(tenantId, new AssetId(entityId.getId()));
Asset asset = edgeCtx.getAssetService().findAssetById(tenantId, new AssetId(entityId.getId()));
if (asset != null) {
customerId = asset.getCustomerId();
metaData.putValue("assetName", asset.getName());
@ -155,7 +182,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
}
}
case ENTITY_VIEW -> {
EntityView entityView = entityViewService.findEntityViewById(tenantId, new EntityViewId(entityId.getId()));
EntityView entityView = edgeCtx.getEntityViewService().findEntityViewById(tenantId, new EntityViewId(entityId.getId()));
if (entityView != null) {
customerId = entityView.getCustomerId();
metaData.putValue("entityViewName", entityView.getName());
@ -163,7 +190,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
}
}
case EDGE -> {
Edge edge = edgeService.findEdgeById(tenantId, new EdgeId(entityId.getId()));
Edge edge = edgeCtx.getEdgeService().findEdgeById(tenantId, new EdgeId(entityId.getId()));
if (edge != null) {
customerId = edge.getCustomerId();
metaData.putValue("edgeName", edge.getName());
@ -182,7 +209,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
metaData.putValue("ts", tsKv.getTs() + "");
var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.POST_TELEMETRY_REQUEST, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
edgeCtx.getClusterService().pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
futureToSet.set(null);
@ -226,7 +253,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
edgeCtx.getClusterService().pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
futureToSet.set(null);
@ -256,7 +283,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.ATTRIBUTES_UPDATED, entityId,
customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
edgeCtx.getClusterService().pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
futureToSet.set(null);
@ -284,11 +311,11 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
String scope = attributeDeleteMsg.getScope();
List<String> attributeKeys = attributeDeleteMsg.getAttributeNamesList();
ListenableFuture<List<String>> removeAllFuture = attributesService.removeAll(tenantId, entityId, AttributeScope.valueOf(scope), attributeKeys);
ListenableFuture<List<String>> removeAllFuture = edgeCtx.getAttributesService().removeAll(tenantId, entityId, AttributeScope.valueOf(scope), attributeKeys);
return Futures.transformAsync(removeAllFuture, removeAttributes -> {
if (EntityType.DEVICE.name().equals(entityType)) {
SettableFuture<Void> futureToSet = SettableFuture.create();
tbClusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete(
edgeCtx.getClusterService().pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete(
tenantId, (DeviceId) entityId, scope, attributeKeys), new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {

23
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/tenant/TenantEdgeProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.tenant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.Tenant;
@ -30,6 +31,7 @@ import org.thingsboard.server.gen.edge.v1.TenantUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.tenant.TenantMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.tenant.TenantMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
@ -37,28 +39,27 @@ import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@TbCoreComponent
public class TenantEdgeProcessor extends BaseEdgeProcessor {
@Autowired
private TenantMsgConstructorFactory tenantMsgConstructorFactory;
public DownlinkMsg convertTenantEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
TenantId tenantId = new TenantId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = ((TenantMsgConstructor) tenantMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion));
if (EdgeEventActionType.UPDATED.equals(edgeEvent.getAction())) {
Tenant tenant = tenantService.findTenantById(tenantId);
Tenant tenant = edgeCtx.getTenantService().findTenantById(tenantId);
if (tenant != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
TenantUpdateMsg tenantUpdateMsg = ((TenantMsgConstructor)
tenantMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion))
.constructTenantUpdateMsg(msgType, tenant);
TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(tenantId, tenant.getTenantProfileId());
TenantProfileUpdateMsg tenantProfileUpdateMsg = ((TenantMsgConstructor)
tenantMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion))
.constructTenantProfileUpdateMsg(msgType, tenantProfile, edgeVersion);
downlinkMsg = DownlinkMsg.newBuilder()
TenantUpdateMsg tenantUpdateMsg = msgConstructor.constructTenantUpdateMsg(msgType, tenant);
TenantProfile tenantProfile = edgeCtx.getTenantProfileService().findTenantProfileById(tenantId, tenant.getTenantProfileId());
TenantProfileUpdateMsg tenantProfileUpdateMsg = msgConstructor.constructTenantProfileUpdateMsg(msgType, tenantProfile, edgeVersion);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addTenantUpdateMsg(tenantUpdateMsg)
.addTenantProfileUpdateMsg(tenantProfileUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

17
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/tenant/TenantProfileEdgeProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.tenant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.TenantProfile;
@ -28,6 +29,7 @@ import org.thingsboard.server.gen.edge.v1.TenantProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.tenant.TenantMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.tenant.TenantMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
@ -35,23 +37,24 @@ import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@TbCoreComponent
public class TenantProfileEdgeProcessor extends BaseEdgeProcessor {
@Autowired
private TenantMsgConstructorFactory tenantMsgConstructorFactory;
public DownlinkMsg convertTenantProfileEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
TenantProfileId tenantProfileId = new TenantProfileId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = ((TenantMsgConstructor) tenantMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion));
if (EdgeEventActionType.UPDATED.equals(edgeEvent.getAction())) {
TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(edgeEvent.getTenantId(), tenantProfileId);
TenantProfile tenantProfile = edgeCtx.getTenantProfileService().findTenantProfileById(edgeEvent.getTenantId(), tenantProfileId);
if (tenantProfile != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
TenantProfileUpdateMsg tenantProfileUpdateMsg = ((TenantMsgConstructor)
tenantMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion))
.constructTenantProfileUpdateMsg(msgType, tenantProfile, edgeVersion);
downlinkMsg = DownlinkMsg.newBuilder()
TenantProfileUpdateMsg tenantProfileUpdateMsg = msgConstructor.constructTenantProfileUpdateMsg(msgType, tenantProfile, edgeVersion);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addTenantProfileUpdateMsg(tenantProfileUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

38
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/user/UserEdgeProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.user;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.User;
@ -28,6 +29,7 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.UserCredentialsUpdateMsg;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.user.UserMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.user.UserMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
@ -35,43 +37,45 @@ import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@TbCoreComponent
public class UserEdgeProcessor extends BaseEdgeProcessor {
@Autowired
private UserMsgConstructorFactory userMsgConstructorFactory;
public DownlinkMsg convertUserEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
UserId userId = new UserId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (UserMsgConstructor) userMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
User user = userService.findUserById(edgeEvent.getTenantId(), userId);
User user = edgeCtx.getUserService().findUserById(edgeEvent.getTenantId(), userId);
if (user != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
DownlinkMsg.Builder builder = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addUserUpdateMsg(((UserMsgConstructor) userMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructUserUpdatedMsg(msgType, user));
UserCredentials userCredentialsByUserId = userService.findUserCredentialsByUserId(edgeEvent.getTenantId(), userId);
.addUserUpdateMsg(msgConstructor.constructUserUpdatedMsg(msgType, user));
UserCredentials userCredentialsByUserId = edgeCtx.getUserService().findUserCredentialsByUserId(edgeEvent.getTenantId(), userId);
if (userCredentialsByUserId != null && userCredentialsByUserId.isEnabled()) {
UserCredentialsUpdateMsg userCredentialsUpdateMsg =
((UserMsgConstructor) userMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructUserCredentialsUpdatedMsg(userCredentialsByUserId);
builder.addUserCredentialsUpdateMsg(userCredentialsUpdateMsg);
builder.addUserCredentialsUpdateMsg(msgConstructor.constructUserCredentialsUpdatedMsg(userCredentialsByUserId));
}
downlinkMsg = builder.build();
return builder.build();
}
}
case DELETED -> downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addUserUpdateMsg(((UserMsgConstructor) userMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructUserDeleteMsg(userId))
.build();
case DELETED -> {
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addUserUpdateMsg(msgConstructor.constructUserDeleteMsg(userId))
.build();
}
case CREDENTIALS_UPDATED -> {
UserCredentials userCredentialsByUserId = userService.findUserCredentialsByUserId(edgeEvent.getTenantId(), userId);
UserCredentials userCredentialsByUserId = edgeCtx.getUserService().findUserCredentialsByUserId(edgeEvent.getTenantId(), userId);
if (userCredentialsByUserId != null && userCredentialsByUserId.isEnabled()) {
UserCredentialsUpdateMsg userCredentialsUpdateMsg =
((UserMsgConstructor) userMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructUserCredentialsUpdatedMsg(userCredentialsByUserId);
downlinkMsg = DownlinkMsg.newBuilder()
UserCredentialsUpdateMsg userCredentialsUpdateMsg = msgConstructor.constructUserCredentialsUpdatedMsg(userCredentialsByUserId);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addUserCredentialsUpdateMsg(userCredentialsUpdateMsg)
.build();
}
}
}
return downlinkMsg;
return null;
}
}

23
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetBundleEdgeProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.widget;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent;
@ -27,6 +28,7 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.WidgetsBundleUpdateMsg;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.widget.WidgetMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.widget.WidgetMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
import java.util.List;
@ -36,33 +38,34 @@ import java.util.List;
@TbCoreComponent
public class WidgetBundleEdgeProcessor extends BaseEdgeProcessor {
@Autowired
private WidgetMsgConstructorFactory widgetMsgConstructorFactory;
public DownlinkMsg convertWidgetsBundleEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = ((WidgetMsgConstructor) widgetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion));
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(edgeEvent.getTenantId(), widgetsBundleId);
WidgetsBundle widgetsBundle = edgeCtx.getWidgetsBundleService().findWidgetsBundleById(edgeEvent.getTenantId(), widgetsBundleId);
if (widgetsBundle != null) {
List<String> widgets = widgetTypeService.findWidgetFqnsByWidgetsBundleId(edgeEvent.getTenantId(), widgetsBundleId);
List<String> widgets = edgeCtx.getWidgetTypeService().findWidgetFqnsByWidgetsBundleId(edgeEvent.getTenantId(), widgetsBundleId);
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
WidgetsBundleUpdateMsg widgetsBundleUpdateMsg =
((WidgetMsgConstructor) widgetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructWidgetsBundleUpdateMsg(msgType, widgetsBundle, widgets);
downlinkMsg = DownlinkMsg.newBuilder()
WidgetsBundleUpdateMsg widgetsBundleUpdateMsg = msgConstructor.constructWidgetsBundleUpdateMsg(msgType, widgetsBundle, widgets);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addWidgetsBundleUpdateMsg(widgetsBundleUpdateMsg)
.build();
}
}
case DELETED -> {
WidgetsBundleUpdateMsg widgetsBundleUpdateMsg =
((WidgetMsgConstructor) widgetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructWidgetsBundleDeleteMsg(widgetsBundleId);
downlinkMsg = DownlinkMsg.newBuilder()
WidgetsBundleUpdateMsg widgetsBundleUpdateMsg = msgConstructor.constructWidgetsBundleDeleteMsg(widgetsBundleId);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addWidgetsBundleUpdateMsg(widgetsBundleUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

21
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetTypeEdgeProcessor.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.widget;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent;
@ -27,6 +28,7 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.widget.WidgetMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.widget.WidgetMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
@ -34,32 +36,33 @@ import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@TbCoreComponent
public class WidgetTypeEdgeProcessor extends BaseEdgeProcessor {
@Autowired
private WidgetMsgConstructorFactory widgetMsgConstructorFactory;
public DownlinkMsg convertWidgetTypeEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) {
WidgetTypeId widgetTypeId = new WidgetTypeId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
var msgConstructor = (WidgetMsgConstructor) widgetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion);
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
WidgetTypeDetails widgetTypeDetails = widgetTypeService.findWidgetTypeDetailsById(edgeEvent.getTenantId(), widgetTypeId);
WidgetTypeDetails widgetTypeDetails = edgeCtx.getWidgetTypeService().findWidgetTypeDetailsById(edgeEvent.getTenantId(), widgetTypeId);
if (widgetTypeDetails != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
WidgetTypeUpdateMsg widgetTypeUpdateMsg =
((WidgetMsgConstructor) widgetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructWidgetTypeUpdateMsg(msgType, widgetTypeDetails, edgeVersion);
downlinkMsg = DownlinkMsg.newBuilder()
WidgetTypeUpdateMsg widgetTypeUpdateMsg = msgConstructor.constructWidgetTypeUpdateMsg(msgType, widgetTypeDetails, edgeVersion);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addWidgetTypeUpdateMsg(widgetTypeUpdateMsg)
.build();
}
}
case DELETED -> {
WidgetTypeUpdateMsg widgetTypeUpdateMsg =
((WidgetMsgConstructor) widgetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructWidgetTypeDeleteMsg(widgetTypeId);
downlinkMsg = DownlinkMsg.newBuilder()
WidgetTypeUpdateMsg widgetTypeUpdateMsg = msgConstructor.constructWidgetTypeDeleteMsg(widgetTypeId);
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addWidgetTypeUpdateMsg(widgetTypeUpdateMsg)
.build();
}
}
return downlinkMsg;
return null;
}
}

6
application/src/main/java/org/thingsboard/server/service/entitiy/EntityStateSourcingListener.java

@ -57,13 +57,13 @@ import org.thingsboard.server.dao.tenant.TenantService;
import java.util.Set;
@Slf4j
@Component
@RequiredArgsConstructor
@Slf4j
public class EntityStateSourcingListener {
private final TbClusterService tbClusterService;
private final TenantService tenantService;
private final TbClusterService tbClusterService;
@PostConstruct
public void init() {
@ -137,7 +137,7 @@ public class EntityStateSourcingListener {
log.debug("[{}][{}][{}] Handling entity deletion event: {}", tenantId, entityType, entityId, event);
switch (entityType) {
case ASSET, ASSET_PROFILE, ENTITY_VIEW, CUSTOMER, EDGE, NOTIFICATION_RULE -> {
case ASSET, ASSET_PROFILE, EDGE, ENTITY_VIEW, CUSTOMER, NOTIFICATION_RULE -> {
tbClusterService.broadcastEntityStateChangeEvent(tenantId, entityId, ComponentLifecycleEvent.DELETED);
}
case NOTIFICATION_REQUEST -> {

2
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbEdgeConsumerService.java

@ -104,7 +104,7 @@ public class DefaultTbEdgeConsumerService extends AbstractConsumerService<ToEdge
this.mainConsumer = MainQueueConsumerManager.<TbProtoQueueMsg<ToEdgeMsg>, EdgeQueueConfig>builder()
.queueKey(new QueueKey(ServiceType.TB_CORE).withQueueName(DataConstants.EDGE_QUEUE_NAME))
.config(EdgeQueueConfig.of(consumerPerPartition, (int) pollInterval))
.config(EdgeQueueConfig.of(consumerPerPartition, pollInterval))
.msgPackProcessor(this::processMsgs)
.consumerCreator((config, partitionId) -> queueFactory.createEdgeMsgConsumer())
.consumerExecutor(consumersExecutor)

3
application/src/main/java/org/thingsboard/server/service/ttl/AbstractCleanUpService.java

@ -28,7 +28,8 @@ public abstract class AbstractCleanUpService {
private final PartitionService partitionService;
protected boolean isSystemTenantPartitionMine(){
protected boolean isSystemTenantPartitionMine() {
return partitionService.resolve(ServiceType.TB_CORE, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isMyPartition();
}
}

3
application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java

@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.thingsboard.server.dao.edge.EdgeEventDao;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository;
import org.thingsboard.server.queue.discovery.PartitionService;
@ -32,7 +33,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_TABLE_N
@TbCoreComponent
@Slf4j
@Service
@ConditionalOnExpression("${sql.ttl.edge_events.enabled:true} && ${sql.ttl.edge_events.edge_events_ttl:0} > 0")
@ConditionalOnExpression("${edges.enabled:true} && ${sql.ttl.edge_events.edge_events_ttl:0} > 0")
public class EdgeEventsCleanUpService extends AbstractCleanUpService {
public static final String RANDOM_DELAY_INTERVAL_MS_EXPRESSION =

160
application/src/main/java/org/thingsboard/server/service/ttl/KafkaEdgeTopicsCleanUpService.java

@ -0,0 +1,160 @@
/**
* Copyright © 2016-2024 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.ttl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.AttributeScope;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.TopicService;
import org.thingsboard.server.queue.kafka.TbKafkaAdmin;
import org.thingsboard.server.queue.kafka.TbKafkaSettings;
import org.thingsboard.server.queue.kafka.TbKafkaTopicConfigs;
import org.thingsboard.server.queue.util.TbCoreComponent;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import static org.thingsboard.server.service.state.DefaultDeviceStateService.LAST_CONNECT_TIME;
@Slf4j
@Service
@TbCoreComponent
@ConditionalOnExpression("'${queue.type:null}'=='kafka' && ${edges.enabled:true} && ${sql.ttl.edge_events.edge_events_ttl:0} > 0")
public class KafkaEdgeTopicsCleanUpService extends AbstractCleanUpService {
private static final String EDGE_EVENT_TOPIC_NAME = "tb_edge_event.notifications.";
private final TopicService topicService;
private final TenantService tenantService;
private final EdgeService edgeService;
private final AttributesService attributesService;
private final TbKafkaAdmin kafkaAdmin;
@Value("${sql.ttl.edge_events.edge_events_ttl:2628000}")
private long ttlSeconds;
public KafkaEdgeTopicsCleanUpService(PartitionService partitionService, EdgeService edgeService,
TenantService tenantService, AttributesService attributesService,
TopicService topicService, TbKafkaSettings kafkaSettings, TbKafkaTopicConfigs kafkaTopicConfigs) {
super(partitionService);
this.topicService = topicService;
this.tenantService = tenantService;
this.edgeService = edgeService;
this.attributesService = attributesService;
this.kafkaAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getEdgeEventConfigs());
}
@Scheduled(initialDelayString = "#{T(org.apache.commons.lang3.RandomUtils).nextLong(0, ${sql.ttl.edge_events.execution_interval_ms})}", fixedDelayString = "${sql.ttl.edge_events.execution_interval_ms}")
public void cleanUp() {
if (!isSystemTenantPartitionMine()) {
return;
}
Set<String> topics = kafkaAdmin.getAllTopics();
if (topics == null || topics.isEmpty()) {
return;
}
String edgeTopicPrefix = topicService.buildTopicName(EDGE_EVENT_TOPIC_NAME);
List<String> matchingTopics = topics.stream().filter(topic -> topic.startsWith(edgeTopicPrefix)).toList();
if (matchingTopics.isEmpty()) {
log.debug("No matching topics found with prefix [{}]. Skipping cleanup.", edgeTopicPrefix);
return;
}
Map<TenantId, List<EdgeId>> tenantEdgeMap = extractTenantAndEdgeIds(matchingTopics, edgeTopicPrefix);
long currentTimeMillis = System.currentTimeMillis();
long ttlMillis = TimeUnit.SECONDS.toMillis(ttlSeconds);
tenantEdgeMap.forEach((tenantId, edgeIds) -> processTenantCleanUp(tenantId, edgeIds, ttlMillis, currentTimeMillis));
}
private void processTenantCleanUp(TenantId tenantId, List<EdgeId> edgeIds, long ttlMillis, long currentTimeMillis) {
boolean tenantExists = tenantService.tenantExists(tenantId);
if (tenantExists) {
for (EdgeId edgeId : edgeIds) {
try {
attributesService.find(tenantId, edgeId, AttributeScope.SERVER_SCOPE, LAST_CONNECT_TIME).get()
.flatMap(AttributeKvEntry::getLongValue)
.filter(lastConnectTime -> isTopicExpired(lastConnectTime, ttlMillis, currentTimeMillis))
.ifPresentOrElse(lastConnectTime -> {
String topic = topicService.buildEdgeEventNotificationsTopicPartitionInfo(tenantId, edgeId).getTopic();
if (kafkaAdmin.isTopicEmpty(topic)) {
kafkaAdmin.deleteTopic(topic);
log.info("[{}] Removed outdated topic {} for edge {} older than {}",
tenantId, topic, edgeId, Date.from(Instant.ofEpochMilli(currentTimeMillis - ttlMillis)));
}
}, () -> {
Edge edge = edgeService.findEdgeById(tenantId, edgeId);
if (edge == null) {
String topic = topicService.buildEdgeEventNotificationsTopicPartitionInfo(tenantId, edgeId).getTopic();
kafkaAdmin.deleteTopic(topic);
log.info("[{}] Removed topic {} for deleted edge {}", tenantId, topic, edgeId);
}
});
} catch (Exception e) {
log.error("[{}] Failed to delete topic for edge {}", tenantId, edgeId, e);
}
}
} else {
for (EdgeId edgeId : edgeIds) {
String topic = topicService.buildEdgeEventNotificationsTopicPartitionInfo(tenantId, edgeId).getTopic();
kafkaAdmin.deleteTopic(topic);
}
log.info("[{}] Removed topics for not existing tenant and edges {}", tenantId, edgeIds);
}
}
private boolean isTopicExpired(long lastConnectTime, long ttlMillis, long currentTimeMillis) {
return lastConnectTime + ttlMillis < currentTimeMillis;
}
private Map<TenantId, List<EdgeId>> extractTenantAndEdgeIds(List<String> topics, String prefix) {
Map<TenantId, List<EdgeId>> tenantEdgeMap = new HashMap<>();
for (String topic : topics) {
try {
String remaining = topic.substring(prefix.length());
String[] parts = remaining.split("\\.");
TenantId tenantId = new TenantId(UUID.fromString(parts[0]));
EdgeId edgeId = new EdgeId(UUID.fromString(parts[1]));
tenantEdgeMap.computeIfAbsent(tenantId, id -> new ArrayList<>()).add(edgeId);
} catch (Exception e) {
log.warn("Failed to extract TenantId and EdgeId from topic [{}]", topic, e);
}
}
return tenantEdgeMap;
}
}

7
application/src/main/resources/thingsboard.yml

@ -1532,6 +1532,11 @@ queue:
# tb_rule_engine.sq:
# - key: max.poll.records
# value: "${TB_QUEUE_KAFKA_SQ_MAX_POLL_RECORDS:1024}"
tb_edge_event.notifications:
# Example of specific consumer properties value per topic for edge event
- key: max.poll.records
# Example of specific consumer properties value per topic for edge event
value: "${TB_QUEUE_KAFKA_EDGE_EVENT_MAX_POLL_RECORDS:50}"
tb_housekeeper:
# Consumer properties for Housekeeper tasks topic
- key: max.poll.records
@ -1569,6 +1574,8 @@ queue:
housekeeper-reprocessing: "${TB_QUEUE_KAFKA_HOUSEKEEPER_REPROCESSING_TOPIC_PROPERTIES:retention.ms:7776000000;segment.bytes:52428800;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
# Kafka properties for Edge topic
edge: "${TB_QUEUE_KAFKA_EDGE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
# Kafka properties for Edge event topic
edge-event: "${TB_QUEUE_KAFKA_EDGE_EVENT_TOPIC_PROPERTIES:retention.ms:2592000000;segment.bytes:52428800;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
consumer-stats:
# Prints lag between consumer group offset and last messages offset in Kafka topics
enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}"

2
application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java

@ -125,7 +125,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
protected EdgeImitator edgeImitator;
protected Edge edge;
private Random random = new Random();
private final Random random = new Random();
@Autowired
protected EdgeEventService edgeEventService;

2
application/src/test/resources/logback-test.xml

@ -19,7 +19,7 @@
<logger name="org.thingsboard.server.service.script" level="INFO"/>
<!-- mute TelemetryEdgeSqlTest that causes a lot of randomly generated errors -->
<logger name="org.thingsboard.server.service.edge.rpc.EdgeGrpcSession" level="OFF"/>
<logger name="org.thingsboard.server.service.edge.rpc.PostgresEdgeGrpcSession" level="OFF"/>
<!-- LwM2m lifecycle debug for the test scope -->
<logger name="org.thingsboard.server.transport.lwm2m.server.downlink.DefaultLwM2mDownlinkMsgHandler" level="TRACE"/>

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

@ -28,9 +28,6 @@ public interface EdgeEventService {
PageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, Long seqIdStart, Long seqIdEnd, TimePageLink pageLink);
/**
* Executes stored procedure to cleanup old edge events.
* @param ttl the ttl for edge events in seconds
*/
void cleanupEvents(long ttl);
}

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

@ -32,7 +32,6 @@ import org.thingsboard.server.dao.entity.EntityDaoService;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
public interface EdgeService extends EntityDaoService {
@ -56,6 +55,8 @@ public interface EdgeService extends EntityDaoService {
void deleteEdge(TenantId tenantId, EdgeId edgeId);
PageData<EdgeId> findEdgeIdsByTenantId(TenantId tenantId, PageLink pageLink);
PageData<Edge> findEdgesByTenantId(TenantId tenantId, PageLink pageLink);
PageData<Edge> findEdgesByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink);

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

@ -143,5 +143,6 @@ public class DataConstants {
public static final String QUEUE_NAME = "queueName";
public static final String EDGE_QUEUE_NAME = "Edge";
public static final String EDGE_EVENT_QUEUE_NAME = "EdgeEvent";
}

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

@ -24,6 +24,7 @@ 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 java.io.Serial;
import java.util.UUID;
@Data
@ -31,6 +32,7 @@ import java.util.UUID;
@ToString(callSuper = true)
public class EdgeEvent extends BaseData<EdgeEventId> {
@Serial
private static final long serialVersionUID = 5548866356798094088L;
private long seqId;
@ -49,4 +51,5 @@ public class EdgeEvent extends BaseData<EdgeEventId> {
public EdgeEvent(EdgeEventId id) {
super(id);
}
}

2
common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java

@ -136,7 +136,7 @@ public class EdgeGrpcClient implements EdgeRpcClient {
.setConnectRequestMsg(ConnectRequestMsg.newBuilder()
.setEdgeRoutingKey(edgeKey)
.setEdgeSecret(edgeSecret)
.setEdgeVersion(EdgeVersion.V_3_8_0)
.setEdgeVersion(EdgeVersion.V_3_9_0)
.setMaxInboundMessageSize(maxInboundMessageSize)
.build())
.build());

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

@ -40,6 +40,7 @@ enum EdgeVersion {
V_3_6_4 = 6;
V_3_7_0 = 7;
V_3_8_0 = 8;
V_3_9_0 = 9;
}
/**

3
common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeEventUpdateMsg.java

@ -20,9 +20,12 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.MsgType;
import java.io.Serial;
@Data
public class EdgeEventUpdateMsg implements EdgeSessionMsg {
@Serial
private static final long serialVersionUID = -8050114506822836537L;
private final TenantId tenantId;

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

@ -20,9 +20,14 @@ import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.MsgType;
import java.io.Serial;
@Data
public class EdgeHighPriorityMsg implements EdgeSessionMsg {
@Serial
private static final long serialVersionUID = 2703437686242033551L;
private final TenantId tenantId;
private final EdgeEvent edgeEvent;

4
common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeSessionMsg.java

@ -18,7 +18,9 @@ package org.thingsboard.server.common.msg.edge;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.MsgType;
public interface EdgeSessionMsg {
import java.io.Serializable;
public interface EdgeSessionMsg extends Serializable {
TenantId getTenantId();

2
common/message/src/main/java/org/thingsboard/server/common/msg/edge/FromEdgeSyncResponse.java

@ -20,11 +20,13 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.MsgType;
import java.io.Serial;
import java.util.UUID;
@Data
public class FromEdgeSyncResponse implements EdgeSessionMsg {
@Serial
private static final long serialVersionUID = -6360890556315667486L;
private final UUID id;

2
common/message/src/main/java/org/thingsboard/server/common/msg/edge/ToEdgeSyncRequest.java

@ -20,11 +20,13 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.MsgType;
import java.io.Serial;
import java.util.UUID;
@Data
public class ToEdgeSyncRequest implements EdgeSessionMsg {
@Serial
private static final long serialVersionUID = -7624597032448212259L;
private final UUID id;

44
common/proto/src/main/java/org/thingsboard/server/common/util/ProtoUtils.java

@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.device.data.CoapDeviceTransportConfigu
import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration;
import org.thingsboard.server.common.data.device.data.PowerMode;
import org.thingsboard.server.common.data.device.data.PowerSavingConfiguration;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.ApiUsageStateId;
@ -181,6 +182,49 @@ public class ProtoUtils {
);
}
public static TransportProtos.EdgeEventMsgProto toProto(EdgeEvent edgeEvent) {
TransportProtos.EdgeEventMsgProto.Builder builder = TransportProtos.EdgeEventMsgProto.newBuilder();
builder.setTenantIdMSB(edgeEvent.getTenantId().getId().getMostSignificantBits());
builder.setTenantIdLSB(edgeEvent.getTenantId().getId().getLeastSignificantBits());
builder.setEntityType(edgeEvent.getType().name());
builder.setAction(edgeEvent.getAction().name());
if (edgeEvent.getEdgeId() != null) {
builder.setEdgeIdMSB(edgeEvent.getEdgeId().getId().getMostSignificantBits());
builder.setEdgeIdLSB(edgeEvent.getEdgeId().getId().getLeastSignificantBits());
}
if (edgeEvent.getEntityId() != null) {
builder.setEntityIdMSB(edgeEvent.getEntityId().getMostSignificantBits());
builder.setEntityIdLSB(edgeEvent.getEntityId().getLeastSignificantBits());
}
if (edgeEvent.getBody() != null) {
builder.setBody(JacksonUtil.toString(edgeEvent.getBody()));
}
return builder.build();
}
public static EdgeEvent fromProto(TransportProtos.EdgeEventMsgProto proto) {
EdgeEvent edgeEvent = new EdgeEvent();
TenantId tenantId = new TenantId(new UUID(proto.getTenantIdMSB(), proto.getTenantIdLSB()));
edgeEvent.setTenantId(tenantId);
edgeEvent.setType(EdgeEventType.valueOf(proto.getEntityType()));
edgeEvent.setAction(EdgeEventActionType.valueOf(proto.getAction()));
if (proto.hasEdgeIdMSB() && proto.hasEdgeIdLSB()) {
edgeEvent.setEdgeId(new EdgeId(new UUID(proto.getEdgeIdMSB(), proto.getEdgeIdLSB())));
}
if (proto.hasEntityIdMSB() && proto.hasEntityIdLSB()) {
edgeEvent.setEntityId(new UUID(proto.getEntityIdMSB(), proto.getEntityIdLSB()));
}
if (proto.hasBody()) {
edgeEvent.setBody(JacksonUtil.toJsonNode(proto.getBody()));
}
return edgeEvent;
}
public static TransportProtos.EdgeHighPriorityMsgProto toProto(EdgeHighPriorityMsg msg) {
TransportProtos.EdgeHighPriorityMsgProto.Builder builder = TransportProtos.EdgeHighPriorityMsgProto.newBuilder()
.setTenantIdMSB(msg.getTenantId().getId().getMostSignificantBits())

17
common/proto/src/main/proto/queue.proto

@ -1127,6 +1127,18 @@ message ComponentLifecycleMsgProto {
ComponentLifecycleEvent event = 6;
}
message EdgeEventMsgProto {
int64 tenantIdMSB = 1;
int64 tenantIdLSB = 2;
string entityType = 3;
string action = 4;
optional int64 edgeIdMSB = 5;
optional int64 edgeIdLSB = 6;
optional int64 entityIdMSB = 7;
optional int64 entityIdLSB = 8;
optional string body = 9;
}
message EdgeNotificationMsgProto {
int64 tenantIdMSB = 1;
int64 tenantIdLSB = 2;
@ -1522,7 +1534,6 @@ message ToCoreNotificationMsg {
RestApiCallResponseMsgProto restApiCallResponseMsg = 50;
}
/* Messages to Edge queue that are handled by ThingsBoard Core Service */
message ToEdgeMsg {
EdgeNotificationMsgProto edgeNotificationMsg = 1;
@ -1536,6 +1547,10 @@ message ToEdgeNotificationMsg {
ComponentLifecycleMsgProto componentLifecycle = 5;
}
message ToEdgeEventNotificationMsg {
EdgeEventMsgProto edgeEventMsg = 1;
}
/* Messages that are handled by ThingsBoard RuleEngine Service */
message ToRuleEngineMsg {
int64 tenantIdMSB = 1;

11
common/queue/src/main/java/org/thingsboard/server/queue/discovery/TopicService.java

@ -17,6 +17,8 @@ package org.thingsboard.server.queue.discovery;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
@ -33,6 +35,7 @@ public class TopicService {
private final ConcurrentMap<String, TopicPartitionInfo> tbCoreNotificationTopics = new ConcurrentHashMap<>();
private final ConcurrentMap<String, TopicPartitionInfo> tbRuleEngineNotificationTopics = new ConcurrentHashMap<>();
private final ConcurrentMap<String, TopicPartitionInfo> tbEdgeNotificationTopics = new ConcurrentHashMap<>();
private final ConcurrentReferenceHashMap<EdgeId, TopicPartitionInfo> tbEdgeEventsNotificationTopics = new ConcurrentReferenceHashMap<>();
/**
* Each Service should start a consumer for messages that target individual service instance based on serviceId.
@ -59,6 +62,14 @@ public class TopicService {
return buildTopicPartitionInfo("tb_edge.notifications." + serviceId, null, null, false);
}
public TopicPartitionInfo getEdgeEventNotificationsTopic(TenantId tenantId, EdgeId edgeId) {
return tbEdgeEventsNotificationTopics.computeIfAbsent(edgeId, id -> buildEdgeEventNotificationsTopicPartitionInfo(tenantId, edgeId));
}
public TopicPartitionInfo buildEdgeEventNotificationsTopicPartitionInfo(TenantId tenantId, EdgeId edgeId) {
return buildTopicPartitionInfo("tb_edge_event.notifications." + tenantId + "." + edgeId, null, null, false);
}
private TopicPartitionInfo buildNotificationsTopicPartitionInfo(ServiceType serviceType, String serviceId) {
return buildTopicPartitionInfo(serviceType.name().toLowerCase() + ".notifications." + serviceId, null, null, false);
}

40
common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaAdmin.java

@ -17,7 +17,10 @@ package org.thingsboard.server.queue.kafka;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.admin.CreateTopicsResult;
import org.apache.kafka.clients.admin.ListOffsetsResult;
import org.apache.kafka.clients.admin.NewTopic;
import org.apache.kafka.clients.admin.OffsetSpec;
import org.apache.kafka.clients.admin.TopicDescription;
import org.apache.kafka.clients.consumer.OffsetAndMetadata;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.errors.TopicExistsException;
@ -25,12 +28,14 @@ import org.thingsboard.server.queue.TbQueueAdmin;
import org.thingsboard.server.queue.util.PropertyUtils;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
/**
* Created by ashvayka on 24.09.18.
@ -116,6 +121,15 @@ public class TbKafkaAdmin implements TbQueueAdmin {
return topics;
}
public Set<String> getAllTopics() {
try {
return settings.getAdminClient().listTopics().names().get();
} catch (InterruptedException | ExecutionException e) {
log.error("Failed to get all topics.", e);
}
return null;
}
public CreateTopicsResult createTopic(NewTopic topic) {
return settings.getAdminClient().createTopics(Collections.singletonList(topic));
}
@ -170,7 +184,33 @@ public class TbKafkaAdmin implements TbQueueAdmin {
log.info("[{}] altered new consumer groupId {}", tp, newGroupId);
break;
}
}
public boolean isTopicEmpty(String topic) {
try {
TopicDescription topicDescription = settings.getAdminClient().describeTopics(Collections.singletonList(topic)).topicNameValues().get(topic).get();
List<TopicPartition> partitions = topicDescription.partitions().stream().map(partitionInfo -> new TopicPartition(topic, partitionInfo.partition())).toList();
Map<TopicPartition, ListOffsetsResult.ListOffsetsResultInfo> beginningOffsets = settings.getAdminClient().listOffsets(partitions.stream()
.collect(Collectors.toMap(partition -> partition, partition -> OffsetSpec.earliest()))).all().get();
Map<TopicPartition, ListOffsetsResult.ListOffsetsResultInfo> endOffsets = settings.getAdminClient().listOffsets(partitions.stream()
.collect(Collectors.toMap(partition -> partition, partition -> OffsetSpec.latest()))).all().get();
for (TopicPartition partition : partitions) {
long beginningOffset = beginningOffsets.get(partition).offset();
long endOffset = endOffsets.get(partition).offset();
if (beginningOffset != endOffset) {
log.debug("Partition [{}] of topic [{}] is not empty. Returning false.", partition.partition(), topic);
return false;
}
}
return true;
} catch (InterruptedException | ExecutionException e) {
log.error("Failed to check if topic [{}] is empty.", topic, e);
return false;
}
}
}

11
common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java

@ -50,6 +50,8 @@ import java.util.Properties;
@Component
public class TbKafkaSettings {
private static final List<String> DYNAMIC_TOPICS = List.of("tb_edge_event.notifications");
@Value("${queue.kafka.bootstrap.servers}")
private String servers;
@ -164,6 +166,15 @@ public class TbKafkaSettings {
consumerPropertiesPerTopic
.getOrDefault(topic, Collections.emptyList())
.forEach(kv -> props.put(kv.getKey(), kv.getValue()));
if (topic != null) {
DYNAMIC_TOPICS.stream()
.filter(topic::startsWith)
.findFirst()
.ifPresent(prefix -> consumerPropertiesPerTopic.getOrDefault(prefix, Collections.emptyList())
.forEach(kv -> props.put(kv.getKey(), kv.getValue())));
}
return props;
}

5
common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaTopicConfigs.java

@ -46,6 +46,8 @@ public class TbKafkaTopicConfigs {
private String vcProperties;
@Value("${queue.kafka.topic-properties.edge:}")
private String edgeProperties;
@Value("${queue.kafka.topic-properties.edge-event:}")
private String edgeEventProperties;
@Value("${queue.kafka.topic-properties.housekeeper:}")
private String housekeeperProperties;
@Value("${queue.kafka.topic-properties.housekeeper-reprocessing:}")
@ -75,6 +77,8 @@ public class TbKafkaTopicConfigs {
private Map<String, String> housekeeperReprocessingConfigs;
@Getter
private Map<String, String> edgeConfigs;
@Getter
private Map<String, String> edgeEventConfigs;
@PostConstruct
private void init() {
@ -92,6 +96,7 @@ public class TbKafkaTopicConfigs {
housekeeperConfigs = PropertyUtils.getProps(housekeeperProperties);
housekeeperReprocessingConfigs = PropertyUtils.getProps(housekeeperReprocessingProperties);
edgeConfigs = PropertyUtils.getProps(edgeProperties);
edgeEventConfigs = PropertyUtils.getProps(edgeEventProperties);
}
}

6
common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java

@ -26,6 +26,7 @@ import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest;
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -281,6 +282,11 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName());
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() {
return null;
}
@PreDestroy
private void destroy() {
if (coreAdmin != null) {

4
common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java

@ -23,10 +23,10 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
@ -131,7 +131,7 @@ public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() {
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() {
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName());
}

5
common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java

@ -204,6 +204,11 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE
return new InMemoryTbQueueProducer<>(storage, topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName());
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() {
return null;
}
@Scheduled(fixedRateString = "${queue.in_memory.stats.print-interval-ms:60000}")
private void printInMemoryStats() {
storage.printStats();

28
common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java

@ -20,11 +20,14 @@ import jakarta.annotation.PreDestroy;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -90,6 +93,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi
private final TbQueueAdmin housekeeperAdmin;
private final TbQueueAdmin housekeeperReprocessingAdmin;
private final TbQueueAdmin edgeAdmin;
private final TbQueueAdmin edgeEventAdmin;
private final AtomicLong consumerCount = new AtomicLong();
@ -128,6 +132,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi
this.housekeeperAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getHousekeeperConfigs());
this.housekeeperReprocessingAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getHousekeeperReprocessingConfigs());
this.edgeAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getEdgeConfigs());
this.edgeEventAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getEdgeEventConfigs());
}
@Override
@ -462,6 +467,29 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi
return requestBuilder.build();
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgConsumer(TenantId tenantId, EdgeId edgeId) {
TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> consumerBuilder = TbKafkaConsumerTemplate.builder();
consumerBuilder.settings(kafkaSettings);
consumerBuilder.topic(topicService.buildTopicName("tb_edge_event.notifications." + tenantId + "." + edgeId));
consumerBuilder.clientId("monolith-to-edge-event-consumer" + serviceInfoProvider.getServiceId());
consumerBuilder.groupId(topicService.buildTopicName("monolith-edge-event-consumer"));
consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeEventNotificationMsg.parseFrom(msg.getData()), msg.getHeaders()));
consumerBuilder.admin(edgeEventAdmin);
consumerBuilder.statsService(consumerStatsService);
return consumerBuilder.build();
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() {
TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> requestBuilder = TbKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("monolith-to-edge-event-" + serviceInfoProvider.getServiceId());
requestBuilder.defaultTopic(topicService.buildTopicName("edge-events"));
requestBuilder.admin(edgeEventAdmin);
return requestBuilder.build();
}
@PreDestroy
private void destroy() {
if (coreAdmin != null) {

28
common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java

@ -20,10 +20,13 @@ import jakarta.annotation.PreDestroy;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -89,6 +92,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory {
private final TbQueueAdmin housekeeperAdmin;
private final TbQueueAdmin housekeeperReprocessingAdmin;
private final TbQueueAdmin edgeAdmin;
private final TbQueueAdmin edgeEventAdmin;
private final AtomicLong consumerCount = new AtomicLong();
@ -128,6 +132,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory {
this.housekeeperAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getHousekeeperConfigs());
this.housekeeperReprocessingAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getHousekeeperReprocessingConfigs());
this.edgeAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getEdgeConfigs());
this.edgeEventAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getEdgeEventConfigs());
}
@Override
@ -411,6 +416,29 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory {
return requestBuilder.build();
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgConsumer(TenantId tenantId, EdgeId edgeId) {
TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> consumerBuilder = TbKafkaConsumerTemplate.builder();
consumerBuilder.settings(kafkaSettings);
consumerBuilder.topic(topicService.buildTopicName("tb_edge_event.notifications." + tenantId + "." + edgeId));
consumerBuilder.clientId("tb-core-edge-event-consumer" + serviceInfoProvider.getServiceId());
consumerBuilder.groupId(topicService.buildTopicName("tb-core-edge-event-consumer"));
consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeEventNotificationMsg.parseFrom(msg.getData()), msg.getHeaders()));
consumerBuilder.admin(edgeEventAdmin);
consumerBuilder.statsService(consumerStatsService);
return consumerBuilder.build();
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() {
TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> requestBuilder = TbKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("tb-core-edge-event-" + serviceInfoProvider.getServiceId());
requestBuilder.defaultTopic(topicService.buildTopicName("edge-events"));
requestBuilder.admin(edgeEventAdmin);
return requestBuilder.build();
}
@PreDestroy
private void destroy() {
if (coreAdmin != null) {

18
common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java

@ -23,10 +23,11 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
@ -79,6 +80,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory {
private final TbQueueAdmin fwUpdatesAdmin;
private final TbQueueAdmin housekeeperAdmin;
private final TbQueueAdmin edgeAdmin;
private final TbQueueAdmin edgeEventAdmin;
private final AtomicLong consumerCount = new AtomicLong();
public KafkaTbRuleEngineQueueFactory(TopicService topicService, TbKafkaSettings kafkaSettings,
@ -108,6 +110,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory {
this.fwUpdatesAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getFwUpdatesConfigs());
this.housekeeperAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getHousekeeperConfigs());
this.edgeAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getEdgeConfigs());
this.edgeEventAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getEdgeEventConfigs());
}
@Override
@ -181,8 +184,8 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory {
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() {
TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<TransportProtos.ToEdgeNotificationMsg>> requestBuilder = TbKafkaProducerTemplate.builder();
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() {
TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToEdgeNotificationMsg>> requestBuilder = TbKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("tb-rule-engine-to-edge-notifications-" + serviceInfoProvider.getServiceId());
requestBuilder.defaultTopic(topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName());
@ -190,6 +193,15 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory {
return requestBuilder.build();
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() {
TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> requestBuilder = TbKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("tb-rule-engine-edge-event-" + serviceInfoProvider.getServiceId());
requestBuilder.admin(edgeEventAdmin);
return requestBuilder.build();
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) {
throw new UnsupportedOperationException("Rule engine consumer should use a partitionId");

6
common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java

@ -26,6 +26,7 @@ import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest;
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -282,6 +283,11 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName());
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() {
return null;
}
@PreDestroy
private void destroy() {
if (coreAdmin != null) {

10
common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java

@ -23,10 +23,11 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
@ -130,10 +131,15 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() {
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() {
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName());
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() {
return null;
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) {
return new TbPubSubConsumerTemplate<>(ruleEngineAdmin, pubSubSettings, topicService.buildTopicName(configuration.getTopic()),

6
common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java

@ -26,6 +26,7 @@ import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest;
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -280,6 +281,11 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName());
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() {
return null;
}
@PreDestroy
private void destroy() {
if (coreAdmin != null) {

4
common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java

@ -23,10 +23,10 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
@ -129,7 +129,7 @@ public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactor
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() {
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() {
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName());
}

6
common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java

@ -25,6 +25,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -279,6 +280,11 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName());
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() {
return null;
}
@PreDestroy
private void destroy() {
if (coreAdmin != null) {

4
common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java

@ -23,10 +23,10 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
@ -129,7 +129,7 @@ public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFact
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() {
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() {
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName());
}

11
common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java

@ -15,9 +15,12 @@
*/
package org.thingsboard.server.queue.provider;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -148,4 +151,12 @@ public interface TbCoreQueueFactory extends TbUsageStatsClientQueueFactory, Hous
TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer();
default TbQueueConsumer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgConsumer(TenantId tenantId, EdgeId edgeId) {
return null;
}
default TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() {
return null;
}
}

8
common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java

@ -19,6 +19,7 @@ import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Service;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -43,6 +44,7 @@ public class TbCoreQueueProducerProvider implements TbQueueProducerProvider {
private TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> toTbCoreNotifications;
private TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> toEdge;
private TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> toEdgeNotifications;
private TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> toEdgeEvents;
private TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> toUsageStats;
private TbQueueProducer<TbProtoQueueMsg<ToVersionControlServiceMsg>> toVersionControl;
private TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> toHousekeeper;
@ -63,6 +65,7 @@ public class TbCoreQueueProducerProvider implements TbQueueProducerProvider {
this.toHousekeeper = tbQueueProvider.createHousekeeperMsgProducer();
this.toEdge = tbQueueProvider.createEdgeMsgProducer();
this.toEdgeNotifications = tbQueueProvider.createEdgeNotificationsMsgProducer();
this.toEdgeEvents = tbQueueProvider.createEdgeEventMsgProducer();
}
@Override
@ -116,4 +119,9 @@ public class TbCoreQueueProducerProvider implements TbQueueProducerProvider {
return toEdgeNotifications;
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> getTbEdgeEventsMsgProducer() {
return toEdgeEvents;
}
}

3
common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java

@ -17,6 +17,7 @@ package org.thingsboard.server.queue.provider;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -88,4 +89,6 @@ public interface TbQueueProducerProvider {
TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> getTbEdgeNotificationsMsgProducer();
TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> getTbEdgeEventsMsgProducer();
}

8
common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java

@ -20,6 +20,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -45,6 +46,7 @@ public class TbRuleEngineProducerProvider implements TbQueueProducerProvider {
private TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> toHousekeeper;
private TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> toEdge;
private TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> toEdgeNotifications;
private TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> toEdgeEvents;
public TbRuleEngineProducerProvider(TbRuleEngineQueueFactory tbQueueProvider) {
this.tbQueueProvider = tbQueueProvider;
@ -61,6 +63,7 @@ public class TbRuleEngineProducerProvider implements TbQueueProducerProvider {
this.toHousekeeper = tbQueueProvider.createHousekeeperMsgProducer();
this.toEdge = tbQueueProvider.createEdgeMsgProducer();
this.toEdgeNotifications = tbQueueProvider.createEdgeNotificationsMsgProducer();
this.toEdgeEvents = tbQueueProvider.createEdgeEventMsgProducer();
}
@Override
@ -98,6 +101,11 @@ public class TbRuleEngineProducerProvider implements TbQueueProducerProvider {
return toEdgeNotifications;
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> getTbEdgeEventsMsgProducer() {
return toEdgeEvents;
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> getTbUsageStatsMsgProducer() {
return toUsageStats;

9
common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineQueueFactory.java

@ -17,10 +17,11 @@ package org.thingsboard.server.queue.provider;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
@ -74,7 +75,11 @@ public interface TbRuleEngineQueueFactory extends TbUsageStatsClientQueueFactory
TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer();
TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer();
TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer();
default TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() {
return null;
}
/**
* Used to consume messages about firmware update notifications to TB Core Service

8
common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java

@ -20,6 +20,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -82,7 +83,7 @@ public class TbTransportQueueProducerProvider implements TbQueueProducerProvider
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> getTbEdgeMsgProducer() {
throw new RuntimeException("Not Implemented! Should not be used Transport!");
throw new RuntimeException("Not Implemented! Should not be used by Transport!");
}
@Override
@ -90,6 +91,11 @@ public class TbTransportQueueProducerProvider implements TbQueueProducerProvider
throw new RuntimeException("Not Implemented! Should not be used by Transport!");
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> getTbEdgeEventsMsgProducer() {
throw new RuntimeException("Not Implemented! Should not be used by Transport!");
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToVersionControlServiceMsg>> getTbVersionControlMsgProducer() {
throw new RuntimeException("Not Implemented! Should not be used by Transport!");

6
common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java

@ -20,6 +20,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg;
@ -86,6 +87,11 @@ public class TbVersionControlProducerProvider implements TbQueueProducerProvider
throw new RuntimeException("Not Implemented! Should not be used by Version Control Service!");
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> getTbEdgeEventsMsgProducer() {
throw new RuntimeException("Not Implemented! Should not be used by Version Control Service!");
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToVersionControlServiceMsg>> getTbVersionControlMsgProducer() {
throw new RuntimeException("Not Implemented! Should not be used by Version Control Service!");

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

@ -15,17 +15,7 @@
*/
package org.thingsboard.server.dao.edge;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.cache.limits.RateLimitService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.edge.EdgeEvent;
@ -35,39 +25,28 @@ import org.thingsboard.server.common.data.limit.LimitedApi;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
import org.thingsboard.server.dao.service.DataValidator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public abstract class BaseEdgeEventService implements EdgeEventService {
@Service
@Slf4j
@RequiredArgsConstructor
public class BaseEdgeEventService implements EdgeEventService {
@Autowired
private EdgeEventDao edgeEventDao;
@Autowired
private RateLimitService rateLimitService;
@Autowired
private DataValidator<EdgeEvent> edgeEventValidator;
private final EdgeEventDao edgeEventDao;
private final RateLimitService rateLimitService;
private final DataValidator<EdgeEvent> edgeEventValidator;
private final ApplicationEventPublisher eventPublisher;
private ExecutorService edgeEventExecutor;
@PostConstruct
public void initExecutor() {
edgeEventExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-event-service"));
@Override
public PageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, Long seqIdStart, Long seqIdEnd, TimePageLink pageLink) {
return edgeEventDao.findEdgeEvents(tenantId.getId(), edgeId, seqIdStart, seqIdEnd, pageLink);
}
@PreDestroy
public void shutdownExecutor() {
if (edgeEventExecutor != null) {
edgeEventExecutor.shutdown();
}
@Override
public void cleanupEvents(long ttl) {
edgeEventDao.cleanupEvents(ttl);
}
@Override
public ListenableFuture<Void> saveAsync(EdgeEvent edgeEvent) {
protected void validateEdgeEvent(EdgeEvent edgeEvent) {
if (!rateLimitService.checkRateLimit(LimitedApi.EDGE_EVENTS, edgeEvent.getTenantId())) {
throw new TbRateLimitsException(EntityType.TENANT);
}
@ -75,30 +54,6 @@ public class BaseEdgeEventService implements EdgeEventService {
throw new TbRateLimitsException(EntityType.EDGE);
}
edgeEventValidator.validate(edgeEvent, EdgeEvent::getTenantId);
ListenableFuture<Void> saveFuture = edgeEventDao.saveAsync(edgeEvent);
Futures.addCallback(saveFuture, new FutureCallback<>() {
@Override
public void onSuccess(Void result) {
eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(edgeEvent.getTenantId())
.entity(edgeEvent).entityId(edgeEvent.getEdgeId()).build());
}
@Override
public void onFailure(@NotNull Throwable throwable) {}
}, edgeEventExecutor);
return saveFuture;
}
@Override
public PageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, Long seqIdStart, Long seqIdEnd, TimePageLink pageLink) {
return edgeEventDao.findEdgeEvents(tenantId.getId(), edgeId, seqIdStart, seqIdEnd, pageLink);
}
@Override
public void cleanupEvents(long ttl) {
edgeEventDao.cleanupEvents(ttl);
}
}

5
dao/src/main/java/org/thingsboard/server/dao/edge/DefaultEdgeSynchronizationManager.java

@ -20,10 +20,11 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.EdgeId;
@Component
@Slf4j
@Getter
@Component
public class DefaultEdgeSynchronizationManager implements EdgeSynchronizationManager {
@Getter
private final ThreadLocal<EdgeId> edgeId = new ThreadLocal<>();
}

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

@ -40,6 +40,8 @@ public interface EdgeDao extends Dao<Edge> {
EdgeInfo findEdgeInfoById(TenantId tenantId, UUID edgeId);
PageData<EdgeId> findEdgeIdsByTenantId(UUID tenantId, PageLink pageLink);
PageData<Edge> findEdgesByTenantId(UUID tenantId, PageLink pageLink);
PageData<Edge> findEdgesByTenantIdAndType(UUID tenantId, String type, PageLink pageLink);

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

@ -56,6 +56,4 @@ public interface EdgeEventDao extends Dao<EdgeEvent> {
*/
void cleanupEvents(long ttl);
void migrateEdgeEvents();
}

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

@ -261,6 +261,14 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
deleteEdge(tenantId, (EdgeId) id);
}
@Override
public PageData<EdgeId> findEdgeIdsByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findEdgeIdsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validatePageLink(pageLink);
return edgeDao.findEdgeIdsByTenantId(tenantId.getId(), pageLink);
}
@Override
public PageData<Edge> findEdgesByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findEdgesByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);

81
dao/src/main/java/org/thingsboard/server/dao/edge/PostgresEdgeEventService.java

@ -0,0 +1,81 @@
/**
* Copyright © 2016-2024 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.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
@Service
@RequiredArgsConstructor
@ConditionalOnExpression("'${queue.type:null}'!='kafka'")
public class PostgresEdgeEventService extends BaseEdgeEventService {
private final EdgeEventDao edgeEventDao;
private final ApplicationEventPublisher eventPublisher;
private ExecutorService edgeEventExecutor;
@PostConstruct
public void initExecutor() {
edgeEventExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-event-service"));
}
@PreDestroy
public void shutdownExecutor() {
if (edgeEventExecutor != null) {
edgeEventExecutor.shutdown();
}
}
@Override
public ListenableFuture<Void> saveAsync(EdgeEvent edgeEvent) {
validateEdgeEvent(edgeEvent);
ListenableFuture<Void> saveFuture = edgeEventDao.saveAsync(edgeEvent);
Futures.addCallback(saveFuture, new FutureCallback<>() {
@Override
public void onSuccess(Void result) {
eventPublisher.publishEvent(SaveEntityEvent.builder()
.tenantId(edgeEvent.getTenantId())
.entityId(edgeEvent.getEdgeId())
.entity(edgeEvent)
.build());
}
@Override
public void onFailure(@NotNull Throwable throwable) {}
}, edgeEventExecutor);
return saveFuture;
}
}

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

@ -129,4 +129,5 @@ public class EdgeEventEntity extends BaseSqlEntity<EdgeEvent> implements BaseEnt
private static long getTs(UUID uuid) {
return (uuid.timestamp() - EPOCH_DIFF) / 10000;
}
}

28
dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java

@ -42,6 +42,12 @@ public interface EdgeRepository extends JpaRepository<EdgeEntity, UUID> {
"WHERE d.id = :edgeId")
EdgeInfoEntity findEdgeInfoById(@Param("edgeId") UUID edgeId);
@Query("SELECT d.id FROM EdgeEntity d WHERE d.tenantId = :tenantId " +
"AND (:textSearch IS NULL OR ilike(d.name, CONCAT('%', :textSearch, '%')) = true)")
Page<UUID> findIdsByTenantId(@Param("tenantId") UUID tenantId,
@Param("textSearch") String textSearch,
Pageable pageable);
@Query("SELECT d FROM EdgeEntity d WHERE d.tenantId = :tenantId " +
"AND (:textSearch IS NULL OR ilike(d.name, CONCAT('%', :textSearch, '%')) = true)")
Page<EdgeEntity> findByTenantId(@Param("tenantId") UUID tenantId,
@ -93,9 +99,9 @@ public interface EdgeRepository extends JpaRepository<EdgeEntity, UUID> {
"AND a.customerId = :customerId " +
"AND (:textSearch IS NULL OR ilike(a.name, CONCAT('%', :textSearch, '%')) = true)")
Page<EdgeInfoEntity> findEdgeInfosByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId,
@Param("customerId") UUID customerId,
@Param("textSearch") String textSearch,
Pageable pageable);
@Param("customerId") UUID customerId,
@Param("textSearch") String textSearch,
Pageable pageable);
@Query("SELECT new org.thingsboard.server.dao.model.sql.EdgeInfoEntity(a, c.title, c.additionalInfo) " +
"FROM EdgeEntity a " +
@ -105,10 +111,10 @@ public interface EdgeRepository extends JpaRepository<EdgeEntity, UUID> {
"AND a.type = :type " +
"AND (:textSearch IS NULL OR ilike(a.name, CONCAT('%', :textSearch, '%')) = true)")
Page<EdgeInfoEntity> findEdgeInfosByTenantIdAndCustomerIdAndType(@Param("tenantId") UUID tenantId,
@Param("customerId") UUID customerId,
@Param("type") String type,
@Param("textSearch") String textSearch,
Pageable pageable);
@Param("customerId") UUID customerId,
@Param("type") String type,
@Param("textSearch") String textSearch,
Pageable pageable);
@Query("SELECT ee FROM EdgeEntity ee, RelationEntity re WHERE ee.tenantId = :tenantId " +
"AND ee.id = re.fromId AND re.fromType = 'EDGE' AND re.relationTypeGroup = 'EDGE' " +
@ -125,10 +131,10 @@ public interface EdgeRepository extends JpaRepository<EdgeEntity, UUID> {
"AND re.relationType = 'Contains' AND re.toId = :entityId AND re.toType = :entityType " +
"AND (:textSearch IS NULL OR ilike(ee.name, CONCAT('%', :textSearch, '%')) = true)")
Page<UUID> findIdsByTenantIdAndEntityId(@Param("tenantId") UUID tenantId,
@Param("entityId") UUID entityId,
@Param("entityType") String entityType,
@Param("textSearch") String textSearch,
Pageable pageable);
@Param("entityId") UUID entityId,
@Param("entityType") String entityType,
@Param("textSearch") String textSearch,
Pageable pageable);
@Query("SELECT ee FROM EdgeEntity ee, TenantEntity te WHERE ee.tenantId = te.id AND te.tenantProfileId = :tenantProfileId ")
Page<EdgeEntity> findByTenantProfileId(@Param("tenantProfileId") UUID tenantProfileId,

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

@ -198,36 +198,6 @@ public class JpaBaseEdgeEventDao extends JpaPartitionedAbstractDao<EdgeEventEnti
partitioningRepository.dropPartitionsBefore(TABLE_NAME, ttl, TimeUnit.HOURS.toMillis(partitionSizeInHours));
}
@Override
public void migrateEdgeEvents() {
long startTime = edgeEventsTtl > 0 ? System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(edgeEventsTtl) : 1629158400000L;
long currentTime = System.currentTimeMillis();
var partitionStepInMs = TimeUnit.HOURS.toMillis(partitionSizeInHours);
long numberOfPartitions = (currentTime - startTime) / partitionStepInMs;
if (numberOfPartitions > 1000) {
String error = "Please adjust your edge event partitioning configuration. Configuration with partition size " +
"of " + partitionSizeInHours + " hours and corresponding TTL will use " + numberOfPartitions + " " +
"(> 1000) partitions which is not recommended!";
log.error(error);
throw new RuntimeException(error);
}
while (startTime < currentTime) {
var endTime = startTime + partitionStepInMs;
log.info("Migrating edge event for time period: {} - {}", startTime, endTime);
callMigrationFunction(startTime, endTime, partitionStepInMs);
startTime = endTime;
}
log.info("Event edge migration finished");
jdbcTemplate.execute("DROP TABLE IF EXISTS old_edge_event");
}
private void callMigrationFunction(long startTime, long endTime, long partitionSIzeInMs) {
jdbcTemplate.update("CALL migrate_edge_event(?, ?, ?)", startTime, endTime, partitionSIzeInMs);
}
@Override
public void createPartition(EdgeEventEntity entity) {
partitioningRepository.createPartitionIfNotExists(TABLE_NAME, entity.getCreatedTime(), TimeUnit.HOURS.toMillis(partitionSizeInHours));

9
dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java

@ -64,6 +64,15 @@ public class JpaEdgeDao extends JpaAbstractDao<EdgeEntity, Edge> implements Edge
return DaoUtil.getData(edgeRepository.findEdgeInfoById(edgeId));
}
@Override
public PageData<EdgeId> findEdgeIdsByTenantId(UUID tenantId, PageLink pageLink) {
return DaoUtil.pageToPageData(
edgeRepository.findIdsByTenantId(
tenantId,
pageLink.getTextSearch(),
DaoUtil.toPageable(pageLink))).mapData(EdgeId::fromUUID);
}
@Override
public PageData<Edge> findEdgesByTenantId(UUID tenantId, PageLink pageLink) {
return DaoUtil.toPageData(

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

Loading…
Cancel
Save