Browse Source

Merge branch 'feature/edge' of github.com:volodymyr-babak/thingsboard into feature/edge

pull/2436/head
deaflynx 6 years ago
parent
commit
cd2e89e834
  1. 4
      application/src/main/java/org/thingsboard/server/controller/AuthController.java
  2. 18
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  3. 11
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  4. 84
      application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java
  5. 11
      application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
  6. 6
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java
  7. 728
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  8. 6
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardUpdateMsgConstructor.java
  9. 33
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceUpdateMsgConstructor.java
  10. 25
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/UserUpdateMsgConstructor.java
  11. 481
      application/src/main/java/org/thingsboard/server/service/edge/rpc/init/DefaultSyncEdgeService.java
  12. 19
      application/src/main/java/org/thingsboard/server/service/edge/rpc/init/SyncEdgeService.java
  13. 9
      application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java
  14. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeEventService.java
  15. 61
      common/data/src/main/java/org/thingsboard/server/common/data/EdgeUtils.java
  16. 3
      common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java
  17. 1
      common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEvent.java
  18. 12
      common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java
  19. 72
      common/edge-api/src/main/proto/edge.proto
  20. 2
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
  21. 23
      dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeEventService.java
  22. 16
      dao/src/main/java/org/thingsboard/server/dao/edge/CassandraEdgeDao.java
  23. 2
      dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java
  24. 12
      dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java
  25. 15
      dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java
  26. 189
      rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java
  27. 2
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java
  28. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAssignToCustomerNode.java
  29. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java
  30. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java
  31. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java
  32. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java
  33. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java
  34. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java
  35. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java
  36. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java
  37. 11
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbUnassignFromCustomerNode.java
  38. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java
  39. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java
  40. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java
  41. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java
  42. 72
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java
  43. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java
  44. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java
  45. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java
  46. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java
  47. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java
  48. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java
  49. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java
  50. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java
  51. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java
  52. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingActionNode.java
  53. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java
  54. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java
  55. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java
  56. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java
  57. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java
  58. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java
  59. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java
  60. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java
  61. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java
  62. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java
  63. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java
  64. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java
  65. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java
  66. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java
  67. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java
  68. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java
  69. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNode.java
  70. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java
  71. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java
  72. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java
  73. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transaction/TbSynchronizationBeginNode.java
  74. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transaction/TbSynchronizationEndNode.java
  75. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java
  76. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java
  77. 6
      ui/src/app/rulechain/rulechain.controller.js
  78. 2
      ui/src/app/rulechain/rulechain.routes.js
  79. 8
      ui/src/app/rulechain/rulechains.controller.js

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

@ -35,6 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -124,6 +125,9 @@ public class AuthController extends BaseController {
} }
userCredentials.setPassword(passwordEncoder.encode(newPassword)); userCredentials.setPassword(passwordEncoder.encode(newPassword));
userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials); userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials);
sendNotificationMsgToEdgeService(getTenantId(), null, userCredentials.getUserId(), EdgeEventType.USER, ActionType.CREDENTIALS_UPDATED);
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }

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

@ -26,12 +26,12 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasName;
@ -39,14 +39,14 @@ import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
@ -85,7 +85,6 @@ import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.ClaimDevicesService; import org.thingsboard.server.dao.device.ClaimDevicesService;
import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
@ -113,7 +112,6 @@ import org.thingsboard.server.service.state.DeviceStateService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import javax.mail.MessagingException; import javax.mail.MessagingException;
import javax.management.relation.Relation;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -209,9 +207,6 @@ public abstract class BaseController {
@Autowired @Autowired
protected EdgeNotificationService edgeNotificationService; protected EdgeNotificationService edgeNotificationService;
@Autowired
protected EdgeEventService edgeEventService;
@Value("${server.log_controller_error_stack_trace}") @Value("${server.log_controller_error_stack_trace}")
@Getter @Getter
private boolean logControllerErrorStackTrace; private boolean logControllerErrorStackTrace;
@ -725,14 +720,17 @@ public abstract class BaseController {
protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityRelation relation, ActionType edgeEventAction) { protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityRelation relation, ActionType edgeEventAction) {
try { try {
sendNotificationMsgToEdgeService(tenantId, null, null, json.writeValueAsString(relation), EdgeEventType.RELATION, edgeEventAction); if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
!relation.getTo().getEntityType().equals(EntityType.EDGE)) {
sendNotificationMsgToEdgeService(tenantId, null, null, json.writeValueAsString(relation), EdgeEventType.RELATION, edgeEventAction);
}
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to push relation to core: {}", relation, e); log.warn("Failed to push relation to core: {}", relation, e);
} }
} }
protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityId entityId, ActionType edgeEventAction) { protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityId entityId, ActionType edgeEventAction) {
EdgeEventType edgeEventType = edgeEventService.getEdgeEventTypeByEntityType(entityId.getEntityType()); EdgeEventType edgeEventType = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType());
if (edgeEventType != null) { if (edgeEventType != null) {
sendNotificationMsgToEdgeService(tenantId, null, entityId, null, edgeEventType, edgeEventAction); sendNotificationMsgToEdgeService(tenantId, null, entityId, null, edgeEventType, edgeEventAction);
} }

11
application/src/main/java/org/thingsboard/server/controller/UserController.java

@ -35,17 +35,14 @@ import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
@ -60,8 +57,6 @@ import org.thingsboard.server.utils.MiscUtils;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import static org.thingsboard.server.controller.EdgeController.EDGE_ID;
@RestController @RestController
@TbCoreComponent @TbCoreComponent
@RequestMapping("/api") @RequestMapping("/api")
@ -167,6 +162,8 @@ public class UserController extends BaseController {
savedUser.getCustomerId(), savedUser.getCustomerId(),
user.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); user.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
sendNotificationMsgToEdgeService(getTenantId(), null, user.getId(), EdgeEventType.USER, user.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
return savedUser; return savedUser;
} catch (Exception e) { } catch (Exception e) {
@ -242,6 +239,8 @@ public class UserController extends BaseController {
user.getCustomerId(), user.getCustomerId(),
ActionType.DELETED, null, strUserId); ActionType.DELETED, null, strUserId);
sendNotificationMsgToEdgeService(getTenantId(), null, user.getId(), EdgeEventType.USER, ActionType.DELETED);
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.USER), logEntityAction(emptyId(EntityType.USER),
null, null,

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

@ -23,12 +23,14 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
@ -36,19 +38,20 @@ import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.IdBased; import org.thingsboard.server.common.data.id.IdBased;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageData; import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.executors.DbCallbackExecutorService;
@ -77,10 +80,10 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
private EdgeService edgeService; private EdgeService edgeService;
@Autowired @Autowired
private RuleChainService ruleChainService; private AlarmService alarmService;
@Autowired @Autowired
private AlarmService alarmService; private UserService userService;
@Autowired @Autowired
private RelationService relationService; private RelationService relationService;
@ -147,12 +150,13 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
switch (edgeEventType) { switch (edgeEventType) {
// TODO: voba - handle edge updates // TODO: voba - handle edge updates
// case EDGE: // case EDGE:
case USER:
case ASSET: case ASSET:
case DEVICE: case DEVICE:
case ENTITY_VIEW: case ENTITY_VIEW:
case DASHBOARD: case DASHBOARD:
case RULE_CHAIN: case RULE_CHAIN:
processEntities(tenantId, edgeNotificationMsg); processEntity(tenantId, edgeNotificationMsg);
break; break;
case ALARM: case ALARM:
processAlarm(tenantId, edgeNotificationMsg); processAlarm(tenantId, edgeNotificationMsg);
@ -171,7 +175,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
} }
} }
private void processEntities(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { private void processEntity(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
ActionType edgeEventActionType = ActionType.valueOf(edgeNotificationMsg.getEdgeEventAction()); ActionType edgeEventActionType = ActionType.valueOf(edgeNotificationMsg.getEdgeEventAction());
EdgeEventType edgeEventType = EdgeEventType.valueOf(edgeNotificationMsg.getEdgeEventType()); EdgeEventType edgeEventType = EdgeEventType.valueOf(edgeNotificationMsg.getEdgeEventType());
EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(edgeEventType, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(edgeEventType, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
@ -179,16 +183,13 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
// TODO: voba - ADDED is not required for CE version ? // TODO: voba - ADDED is not required for CE version ?
// case ADDED: // case ADDED:
case UPDATED: case UPDATED:
case CREDENTIALS_UPDATED:
ListenableFuture<List<EdgeId>> edgeIdsFuture = findRelatedEdgeIdsByEntityId(tenantId, entityId); ListenableFuture<List<EdgeId>> edgeIdsFuture = findRelatedEdgeIdsByEntityId(tenantId, entityId);
Futures.transform(edgeIdsFuture, edgeIds -> { Futures.transform(edgeIdsFuture, edgeIds -> {
if (edgeIds != null && !edgeIds.isEmpty()) { if (edgeIds != null && !edgeIds.isEmpty()) {
for (EdgeId edgeId : edgeIds) { for (EdgeId edgeId : edgeIds) {
try { try {
saveEdgeEvent(tenantId, edgeId, edgeEventType, edgeEventActionType, entityId, null); saveEdgeEvent(tenantId, edgeId, edgeEventType, edgeEventActionType, entityId, null);
if (edgeEventType.equals(EdgeEventType.RULE_CHAIN)) {
RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(tenantId, new RuleChainId(entityId.getId()));
saveEdgeEvent(tenantId, edgeId, EdgeEventType.RULE_CHAIN_METADATA, edgeEventActionType, ruleChainMetaData.getRuleChainId(), null);
}
} catch (Exception e) { } catch (Exception e) {
log.error("[{}] Failed to push event to edge, edgeId [{}], edgeEventType [{}], edgeEventActionType [{}], entityId [{}]", log.error("[{}] Failed to push event to edge, edgeId [{}], edgeEventType [{}], edgeEventActionType [{}], entityId [{}]",
tenantId, edgeId, edgeEventType, edgeEventActionType, entityId, e); tenantId, edgeId, edgeEventType, edgeEventActionType, entityId, e);
@ -245,32 +246,35 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
} }
private void processRelation(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { private void processRelation(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
EntityRelation entityRelation = mapper.convertValue(edgeNotificationMsg.getEntityBody(), EntityRelation.class); EntityRelation relation = mapper.convertValue(edgeNotificationMsg.getEntityBody(), EntityRelation.class);
List<ListenableFuture<List<EdgeId>>> futures = new ArrayList<>(); if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
futures.add(findRelatedEdgeIdsByEntityId(tenantId, entityRelation.getTo())); !relation.getTo().getEntityType().equals(EntityType.EDGE)) {
futures.add(findRelatedEdgeIdsByEntityId(tenantId, entityRelation.getFrom())); List<ListenableFuture<List<EdgeId>>> futures = new ArrayList<>();
ListenableFuture<List<List<EdgeId>>> combinedFuture = Futures.allAsList(futures); futures.add(findRelatedEdgeIdsByEntityId(tenantId, relation.getTo()));
Futures.transform(combinedFuture, listOfListsEdgeIds -> { futures.add(findRelatedEdgeIdsByEntityId(tenantId, relation.getFrom()));
Set<EdgeId> uniqueEdgeIds = new HashSet<>(); ListenableFuture<List<List<EdgeId>>> combinedFuture = Futures.allAsList(futures);
if (listOfListsEdgeIds != null && !listOfListsEdgeIds.isEmpty()) { Futures.transform(combinedFuture, listOfListsEdgeIds -> {
for (List<EdgeId> listOfListsEdgeId : listOfListsEdgeIds) { Set<EdgeId> uniqueEdgeIds = new HashSet<>();
if (listOfListsEdgeId != null) { if (listOfListsEdgeIds != null && !listOfListsEdgeIds.isEmpty()) {
uniqueEdgeIds.addAll(listOfListsEdgeId); for (List<EdgeId> listOfListsEdgeId : listOfListsEdgeIds) {
if (listOfListsEdgeId != null) {
uniqueEdgeIds.addAll(listOfListsEdgeId);
}
} }
} }
} if (!uniqueEdgeIds.isEmpty()) {
if (!uniqueEdgeIds.isEmpty()) { for (EdgeId edgeId : uniqueEdgeIds) {
for (EdgeId edgeId : uniqueEdgeIds) { saveEdgeEvent(tenantId,
saveEdgeEvent(tenantId, edgeId,
edgeId, EdgeEventType.RELATION,
EdgeEventType.RELATION, ActionType.valueOf(edgeNotificationMsg.getEdgeEventAction()),
ActionType.valueOf(edgeNotificationMsg.getEdgeEventAction()), null,
null, mapper.valueToTree(relation));
mapper.valueToTree(entityRelation)); }
} }
} return null;
return null; }, dbCallbackExecutorService);
}, dbCallbackExecutorService); }
} }
private ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) { private ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) {
@ -278,7 +282,8 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
case DEVICE: case DEVICE:
case ASSET: case ASSET:
case ENTITY_VIEW: case ENTITY_VIEW:
ListenableFuture<List<EntityRelation>> originatorEdgeRelationsFuture = relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); ListenableFuture<List<EntityRelation>> originatorEdgeRelationsFuture =
relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
return Futures.transform(originatorEdgeRelationsFuture, originatorEdgeRelations -> { return Futures.transform(originatorEdgeRelationsFuture, originatorEdgeRelations -> {
if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) { if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) {
return Collections.singletonList(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId())); return Collections.singletonList(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId()));
@ -290,6 +295,15 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
return convertToEdgeIds(edgeService.findEdgesByTenantIdAndDashboardId(tenantId, new DashboardId(entityId.getId()))); return convertToEdgeIds(edgeService.findEdgesByTenantIdAndDashboardId(tenantId, new DashboardId(entityId.getId())));
case RULE_CHAIN: case RULE_CHAIN:
return convertToEdgeIds(edgeService.findEdgesByTenantIdAndRuleChainId(tenantId, new RuleChainId(entityId.getId()))); return convertToEdgeIds(edgeService.findEdgesByTenantIdAndRuleChainId(tenantId, new RuleChainId(entityId.getId())));
case USER:
User userById = userService.findUserById(tenantId, new UserId(entityId.getId()));
TextPageData<Edge> edges;
if (userById.getCustomerId() == null || userById.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
edges = edgeService.findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE));
} else {
edges = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, new CustomerId(entityId.getId()), new TextPageLink(Integer.MAX_VALUE));
}
return convertToEdgeIds(Futures.immediateFuture(edges.getData()));
default: default:
return Futures.immediateFuture(Collections.emptyList()); return Futures.immediateFuture(Collections.emptyList());
} }
@ -314,7 +328,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
case ENTITY_VIEW: case ENTITY_VIEW:
return EdgeEventType.ENTITY_VIEW; return EdgeEventType.ENTITY_VIEW;
default: default:
log.info("Unsupported entity type: [{}]", entityType); log.debug("Unsupported entity type: [{}]", entityType);
return null; return null;
} }
} }

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

@ -33,6 +33,9 @@ import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.EdgeEventStorageSettings; import org.thingsboard.server.service.edge.rpc.EdgeEventStorageSettings;
import org.thingsboard.server.service.edge.rpc.constructor.AlarmUpdateMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.AlarmUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.AssetUpdateMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.AssetUpdateMsgConstructor;
@ -49,6 +52,7 @@ import org.thingsboard.server.service.queue.TbClusterService;
import org.thingsboard.server.service.state.DeviceStateService; import org.thingsboard.server.service.state.DeviceStateService;
@Component @Component
@TbCoreComponent
@Data @Data
public class EdgeContextComponent { public class EdgeContextComponent {
@ -56,6 +60,13 @@ public class EdgeContextComponent {
@Autowired @Autowired
private EdgeService edgeService; private EdgeService edgeService;
@Autowired
private PartitionService partitionService;
@Autowired
@Lazy
private TbQueueProducerProvider producerProvider;
@Lazy @Lazy
@Autowired @Autowired
private EdgeNotificationService edgeNotificationService; private EdgeNotificationService edgeNotificationService;

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

@ -26,8 +26,6 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.gen.edge.EdgeRpcServiceGrpc; import org.thingsboard.server.gen.edge.EdgeRpcServiceGrpc;
import org.thingsboard.server.gen.edge.RequestMsg; import org.thingsboard.server.gen.edge.RequestMsg;
import org.thingsboard.server.gen.edge.ResponseMsg; import org.thingsboard.server.gen.edge.ResponseMsg;
@ -48,7 +46,7 @@ import java.util.concurrent.Executors;
public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase { public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase {
private final Map<EdgeId, EdgeGrpcSession> sessions = new ConcurrentHashMap<>(); private final Map<EdgeId, EdgeGrpcSession> sessions = new ConcurrentHashMap<>();
private static final ObjectMapper objectMapper = new ObjectMapper(); private static final ObjectMapper mapper = new ObjectMapper();
@Value("${edges.rpc.port}") @Value("${edges.rpc.port}")
private int rpcPort; private int rpcPort;
@ -102,7 +100,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase {
@Override @Override
public StreamObserver<RequestMsg> handleMsgs(StreamObserver<ResponseMsg> outputStream) { public StreamObserver<RequestMsg> handleMsgs(StreamObserver<ResponseMsg> outputStream) {
return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, objectMapper).getInputStream(); return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, mapper).getInputStream();
} }
private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) { private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) {

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

@ -22,13 +22,13 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
@ -45,6 +45,7 @@ import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
@ -55,7 +56,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.DataType;
import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.page.TimePageData; import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
@ -65,28 +65,45 @@ import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.common.transport.util.JsonUtils;
import org.thingsboard.server.gen.edge.AlarmUpdateMsg; import org.thingsboard.server.gen.edge.AlarmUpdateMsg;
import org.thingsboard.server.gen.edge.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.AttributesRequestMsg;
import org.thingsboard.server.gen.edge.ConnectRequestMsg; import org.thingsboard.server.gen.edge.ConnectRequestMsg;
import org.thingsboard.server.gen.edge.ConnectResponseCode; import org.thingsboard.server.gen.edge.ConnectResponseCode;
import org.thingsboard.server.gen.edge.ConnectResponseMsg; import org.thingsboard.server.gen.edge.ConnectResponseMsg;
import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.DownlinkMsg; import org.thingsboard.server.gen.edge.DownlinkMsg;
import org.thingsboard.server.gen.edge.EdgeConfiguration; import org.thingsboard.server.gen.edge.EdgeConfiguration;
import org.thingsboard.server.gen.edge.EntityDataProto; import org.thingsboard.server.gen.edge.EntityDataProto;
import org.thingsboard.server.gen.edge.EntityUpdateMsg; import org.thingsboard.server.gen.edge.EntityUpdateMsg;
import org.thingsboard.server.gen.edge.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.RelationRequestMsg;
import org.thingsboard.server.gen.edge.RequestMsg; import org.thingsboard.server.gen.edge.RequestMsg;
import org.thingsboard.server.gen.edge.RequestMsgType; import org.thingsboard.server.gen.edge.RequestMsgType;
import org.thingsboard.server.gen.edge.ResponseMsg; import org.thingsboard.server.gen.edge.ResponseMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg; import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.RuleChainUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType; import org.thingsboard.server.gen.edge.UpdateMsgType;
import org.thingsboard.server.gen.edge.UplinkMsg; import org.thingsboard.server.gen.edge.UplinkMsg;
import org.thingsboard.server.gen.edge.UplinkResponseMsg; import org.thingsboard.server.gen.edge.UplinkResponseMsg;
import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.UserCredentialsUpdateMsg;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
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.service.edge.EdgeContextComponent; import org.thingsboard.server.service.edge.EdgeContextComponent;
import java.io.Closeable; import java.io.Closeable;
@ -115,7 +132,7 @@ public final class EdgeGrpcSession implements Closeable {
private final UUID sessionId; private final UUID sessionId;
private final BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener; private final BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener;
private final Consumer<EdgeId> sessionCloseListener; private final Consumer<EdgeId> sessionCloseListener;
private final ObjectMapper objectMapper; private final ObjectMapper mapper;
private EdgeContextComponent ctx; private EdgeContextComponent ctx;
private Edge edge; private Edge edge;
@ -123,14 +140,17 @@ public final class EdgeGrpcSession implements Closeable {
private StreamObserver<ResponseMsg> outputStream; private StreamObserver<ResponseMsg> outputStream;
private boolean connected; private boolean connected;
private TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> ruleEngineMsgProducer;
EdgeGrpcSession(EdgeContextComponent ctx, StreamObserver<ResponseMsg> outputStream, BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener, EdgeGrpcSession(EdgeContextComponent ctx, StreamObserver<ResponseMsg> outputStream, BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener,
Consumer<EdgeId> sessionCloseListener, ObjectMapper objectMapper) { Consumer<EdgeId> sessionCloseListener, ObjectMapper mapper) {
this.sessionId = UUID.randomUUID(); this.sessionId = UUID.randomUUID();
this.ctx = ctx; this.ctx = ctx;
this.outputStream = outputStream; this.outputStream = outputStream;
this.sessionOpenListener = sessionOpenListener; this.sessionOpenListener = sessionOpenListener;
this.sessionCloseListener = sessionCloseListener; this.sessionCloseListener = sessionCloseListener;
this.objectMapper = objectMapper; this.mapper = mapper;
this.ruleEngineMsgProducer = ctx.getProducerProvider().getRuleEngineMsgProducer();
initInputStream(); initInputStream();
} }
@ -147,7 +167,7 @@ public final class EdgeGrpcSession implements Closeable {
outputStream.onError(new RuntimeException(responseMsg.getErrorMsg())); outputStream.onError(new RuntimeException(responseMsg.getErrorMsg()));
} }
if (ConnectResponseCode.ACCEPTED == responseMsg.getResponseCode()) { if (ConnectResponseCode.ACCEPTED == responseMsg.getResponseCode()) {
ctx.getSyncEdgeService().sync(ctx, edge, outputStream); ctx.getSyncEdgeService().sync(edge);
} }
} }
if (connected) { if (connected) {
@ -184,14 +204,23 @@ public final class EdgeGrpcSession implements Closeable {
for (EdgeEvent edgeEvent : pageData.getData()) { for (EdgeEvent edgeEvent : pageData.getData()) {
log.trace("[{}] Processing edge event [{}]", this.sessionId, edgeEvent); log.trace("[{}] Processing edge event [{}]", this.sessionId, edgeEvent);
try { try {
UpdateMsgType msgType = getResponseMsgType(ActionType.valueOf(edgeEvent.getEdgeEventAction())); ActionType edgeEventAction = ActionType.valueOf(edgeEvent.getEdgeEventAction());
if (msgType == null) { switch (edgeEventAction) {
processTelemetryMessage(edgeEvent); case UPDATED:
} else { case ADDED:
processEntityCRUDMessage(edgeEvent, msgType); case ASSIGNED_TO_EDGE:
if (ENTITY_CREATED_RPC_MESSAGE.equals(msgType)) { case DELETED:
pushEntityAttributesToEdge(edgeEvent); case UNASSIGNED_FROM_EDGE:
} case ALARM_ACK:
case ALARM_CLEAR:
case CREDENTIALS_UPDATED:
processEntityMessage(edgeEvent, edgeEventAction);
break;
case ATTRIBUTES_UPDATED:
case ATTRIBUTES_DELETED:
case TIMESERIES_UPDATED:
processTelemetryMessage(edgeEvent);
break;
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during processing records from queue", e); log.error("Exception during processing records from queue", e);
@ -230,7 +259,7 @@ public final class EdgeGrpcSession implements Closeable {
} else { } else {
return 0L; return 0L;
} }
}, MoreExecutors.directExecutor()); }, ctx.getDbCallbackExecutor());
} }
private void updateQueueStartTs(Long newStartTs) { private void updateQueueStartTs(Long newStartTs) {
@ -239,12 +268,10 @@ public final class EdgeGrpcSession implements Closeable {
ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes); ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes);
} }
private void pushEntityAttributesToEdge(EdgeEvent edgeEvent) throws IOException { private void processTelemetryMessage(EdgeEvent edgeEvent) throws IOException {
log.trace("Executing processTelemetryMessage, edgeEvent [{}]", edgeEvent);
EntityId entityId = null; EntityId entityId = null;
switch (edgeEvent.getEdgeEventType()) { switch (edgeEvent.getEdgeEventType()) {
case EDGE:
entityId = edge.getId();
break;
case DEVICE: case DEVICE:
entityId = new DeviceId(edgeEvent.getEntityId()); entityId = new DeviceId(edgeEvent.getEntityId());
break; break;
@ -258,60 +285,12 @@ public final class EdgeGrpcSession implements Closeable {
entityId = new DashboardId(edgeEvent.getEntityId()); entityId = new DashboardId(edgeEvent.getEntityId());
break; break;
} }
if (entityId != null) {
final EntityId finalEntityId = entityId;
ListenableFuture<List<AttributeKvEntry>> ssAttrFuture = ctx.getAttributesService().findAll(edge.getTenantId(), entityId, DataConstants.SERVER_SCOPE);
Futures.transform(ssAttrFuture, ssAttributes -> {
if (ssAttributes != null && !ssAttributes.isEmpty()) {
try {
ObjectNode entityNode = objectMapper.createObjectNode();
for (AttributeKvEntry attr : ssAttributes) {
if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) {
entityNode.put(attr.getKey(), attr.getBooleanValue().get());
} else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) {
entityNode.put(attr.getKey(), attr.getDoubleValue().get());
} else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) {
entityNode.put(attr.getKey(), attr.getLongValue().get());
} else {
entityNode.put(attr.getKey(), attr.getValueAsString());
}
}
log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", finalEntityId, entityNode);
DownlinkMsg value = constructEntityDataProtoMsg(finalEntityId, ActionType.ATTRIBUTES_UPDATED, JsonUtils.parse(objectMapper.writeValueAsString(entityNode)));
outputStream.onNext(ResponseMsg.newBuilder()
.setDownlinkMsg(value).build());
} catch (Exception e) {
log.error("[{}] Failed to send attribute updates to the edge", edge.getName(), e);
}
}
return null;
}, MoreExecutors.directExecutor());
ListenableFuture<List<AttributeKvEntry>> shAttrFuture = ctx.getAttributesService().findAll(edge.getTenantId(), entityId, DataConstants.SHARED_SCOPE);
ListenableFuture<List<AttributeKvEntry>> clAttrFuture = ctx.getAttributesService().findAll(edge.getTenantId(), entityId, DataConstants.CLIENT_SCOPE);
}
}
private void processTelemetryMessage(EdgeEvent edgeEvent) throws IOException {
log.trace("Executing processTelemetryMessage, edgeEvent [{}]", edgeEvent);
EntityId entityId = null;
switch (edgeEvent.getEdgeEventType()) {
case DEVICE:
entityId = new DeviceId(edgeEvent.getEntityId());
break;
case ASSET:
entityId = new AssetId(edgeEvent.getEntityId());
break;
case ENTITY_VIEW:
entityId = new EntityViewId(edgeEvent.getEntityId());
break;
}
if (entityId != null) { if (entityId != null) {
log.debug("Sending telemetry data msg, entityId [{}], body [{}]", edgeEvent.getEntityId(), edgeEvent.getEntityBody()); log.debug("Sending telemetry data msg, entityId [{}], body [{}]", edgeEvent.getEntityId(), edgeEvent.getEntityBody());
DownlinkMsg downlinkMsg; DownlinkMsg downlinkMsg;
try { try {
ActionType actionType = ActionType.valueOf(edgeEvent.getEdgeEventAction()); ActionType actionType = ActionType.valueOf(edgeEvent.getEdgeEventAction());
downlinkMsg = constructEntityDataProtoMsg(entityId, actionType, JsonUtils.parse(objectMapper.writeValueAsString(edgeEvent.getEntityBody()))); downlinkMsg = constructEntityDataProtoMsg(entityId, actionType, JsonUtils.parse(mapper.writeValueAsString(edgeEvent.getEntityBody())));
outputStream.onNext(ResponseMsg.newBuilder() outputStream.onNext(ResponseMsg.newBuilder()
.setDownlinkMsg(downlinkMsg) .setDownlinkMsg(downlinkMsg)
.build()); .build());
@ -322,302 +301,268 @@ public final class EdgeGrpcSession implements Closeable {
} }
} }
private void processEntityCRUDMessage(EdgeEvent edgeEvent, UpdateMsgType msgType) { private void processEntityMessage(EdgeEvent edgeEvent, ActionType edgeEventAction) {
log.trace("Executing processEntityCRUDMessage, edgeEvent [{}], msgType [{}]", edgeEvent, msgType); UpdateMsgType msgType = getResponseMsgType(ActionType.valueOf(edgeEvent.getEdgeEventAction()));
log.trace("Executing processEntityMessage, edgeEvent [{}], edgeEventAction [{}], msgType [{}]", edgeEvent, edgeEventAction, msgType);
switch (edgeEvent.getEdgeEventType()) { switch (edgeEvent.getEdgeEventType()) {
case EDGE: case EDGE:
// TODO: voba - add edge update logic // TODO: voba - add edge update logic
break; break;
case DEVICE: case DEVICE:
processDeviceCRUD(edgeEvent, msgType); processDevice(edgeEvent, msgType, edgeEventAction);
break; break;
case ASSET: case ASSET:
processAssetCRUD(edgeEvent, msgType); processAsset(edgeEvent, msgType, edgeEventAction);
break; break;
case ENTITY_VIEW: case ENTITY_VIEW:
processEntityViewCRUD(edgeEvent, msgType); processEntityView(edgeEvent, msgType, edgeEventAction);
break; break;
case DASHBOARD: case DASHBOARD:
processDashboardCRUD(edgeEvent, msgType); processDashboard(edgeEvent, msgType, edgeEventAction);
break; break;
case RULE_CHAIN: case RULE_CHAIN:
processRuleChainCRUD(edgeEvent, msgType); processRuleChain(edgeEvent, msgType, edgeEventAction);
break; break;
case RULE_CHAIN_METADATA: case RULE_CHAIN_METADATA:
processRuleChainMetadataCRUD(edgeEvent, msgType); processRuleChainMetadata(edgeEvent, msgType);
break; break;
case ALARM: case ALARM:
processAlarmCRUD(edgeEvent, msgType); processAlarm(edgeEvent, msgType);
break; break;
case USER: case USER:
processUserCRUD(edgeEvent, msgType); processUser(edgeEvent, msgType, edgeEventAction);
break; break;
case RELATION: case RELATION:
processRelationCRUD(edgeEvent, msgType); processRelation(edgeEvent, msgType);
break; break;
} }
} }
private void processDeviceCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { private void processDevice(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeActionType) {
DeviceId deviceId = new DeviceId(edgeEvent.getEntityId()); DeviceId deviceId = new DeviceId(edgeEvent.getEntityId());
switch (msgType) { EntityUpdateMsg entityUpdateMsg = null;
case ENTITY_CREATED_RPC_MESSAGE: switch (edgeActionType) {
case ENTITY_UPDATED_RPC_MESSAGE: case ADDED:
case DEVICE_CONFLICT_RPC_MESSAGE: case UPDATED:
ListenableFuture<Device> deviceFuture = ctx.getDeviceService().findDeviceByIdAsync(edgeEvent.getTenantId(), deviceId); case ASSIGNED_TO_EDGE:
Futures.addCallback(deviceFuture, Device device = ctx.getDeviceService().findDeviceById(edgeEvent.getTenantId(), deviceId);
new FutureCallback<Device>() { if (device != null) {
@Override DeviceUpdateMsg deviceUpdateMsg =
public void onSuccess(@Nullable Device device) { ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(msgType, device);
if (device != null) { entityUpdateMsg = EntityUpdateMsg.newBuilder()
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() .setDeviceUpdateMsg(deviceUpdateMsg)
.setDeviceUpdateMsg(ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(msgType, device)) .build();
.build(); }
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
@Override
public void onFailure(Throwable t) {
log.warn("Can't processDeviceCRUD, edgeEvent [{}]", edgeEvent, t);
}
}, ctx.getDbCallbackExecutor());
break; break;
case ENTITY_DELETED_RPC_MESSAGE: case DELETED:
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() case UNASSIGNED_FROM_EDGE:
.setDeviceUpdateMsg(ctx.getDeviceUpdateMsgConstructor().constructDeviceDeleteMsg(deviceId)) DeviceUpdateMsg deviceUpdateMsg =
ctx.getDeviceUpdateMsgConstructor().constructDeviceDeleteMsg(deviceId);
entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setDeviceUpdateMsg(deviceUpdateMsg)
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder() break;
.setEntityUpdateMsg(entityUpdateMsg) case CREDENTIALS_UPDATED:
.build()); DeviceCredentials deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(edge.getTenantId(), deviceId);
if (deviceCredentials != null) {
DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg =
ctx.getDeviceUpdateMsgConstructor().constructDeviceCredentialsUpdatedMsg(deviceCredentials);
entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setDeviceCredentialsUpdateMsg(deviceCredentialsUpdateMsg)
.build();
}
break;
}
if (entityUpdateMsg != null) {
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
} }
} }
private void processAssetCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { private void processAsset(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
AssetId assetId = new AssetId(edgeEvent.getEntityId()); AssetId assetId = new AssetId(edgeEvent.getEntityId());
switch (msgType) { EntityUpdateMsg entityUpdateMsg = null;
case ENTITY_CREATED_RPC_MESSAGE: switch (edgeEventAction) {
case ENTITY_UPDATED_RPC_MESSAGE: case ADDED:
case DEVICE_CONFLICT_RPC_MESSAGE: case UPDATED:
ListenableFuture<Asset> assetFuture = ctx.getAssetService().findAssetByIdAsync(edgeEvent.getTenantId(), assetId); case ASSIGNED_TO_EDGE:
Futures.addCallback(assetFuture, Asset asset = ctx.getAssetService().findAssetById(edgeEvent.getTenantId(), assetId);
new FutureCallback<Asset>() { if (asset != null) {
@Override AssetUpdateMsg assetUpdateMsg =
public void onSuccess(@Nullable Asset asset) { ctx.getAssetUpdateMsgConstructor().constructAssetUpdatedMsg(msgType, asset);
if (asset != null) { entityUpdateMsg = EntityUpdateMsg.newBuilder()
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() .setAssetUpdateMsg(assetUpdateMsg)
.setAssetUpdateMsg(ctx.getAssetUpdateMsgConstructor().constructAssetUpdatedMsg(msgType, asset)) .build();
.build(); }
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
@Override
public void onFailure(Throwable t) {
log.warn("Can't processAssetCRUD, edgeEvent [{}]", edgeEvent, t);
}
}, ctx.getDbCallbackExecutor());
break; break;
case ENTITY_DELETED_RPC_MESSAGE: case DELETED:
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() case UNASSIGNED_FROM_EDGE:
.setAssetUpdateMsg(ctx.getAssetUpdateMsgConstructor().constructAssetDeleteMsg(assetId)) AssetUpdateMsg assetUpdateMsg =
ctx.getAssetUpdateMsgConstructor().constructAssetDeleteMsg(assetId);
entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setAssetUpdateMsg(assetUpdateMsg)
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
break; break;
} }
if (entityUpdateMsg != null) {
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
} }
private void processEntityViewCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { private void processEntityView(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
EntityViewId entityViewId = new EntityViewId(edgeEvent.getEntityId()); EntityViewId entityViewId = new EntityViewId(edgeEvent.getEntityId());
switch (msgType) { EntityUpdateMsg entityUpdateMsg = null;
case ENTITY_CREATED_RPC_MESSAGE: switch (edgeEventAction) {
case ENTITY_UPDATED_RPC_MESSAGE: case ADDED:
case DEVICE_CONFLICT_RPC_MESSAGE: case UPDATED:
ListenableFuture<EntityView> entityViewFuture = ctx.getEntityViewService().findEntityViewByIdAsync(edgeEvent.getTenantId(), entityViewId); case ASSIGNED_TO_EDGE:
Futures.addCallback(entityViewFuture, EntityView entityView = ctx.getEntityViewService().findEntityViewById(edgeEvent.getTenantId(), entityViewId);
new FutureCallback<EntityView>() { if (entityView != null) {
@Override EntityViewUpdateMsg entityViewUpdateMsg =
public void onSuccess(@Nullable EntityView entityView) { ctx.getEntityViewUpdateMsgConstructor().constructEntityViewUpdatedMsg(msgType, entityView);
if (entityView != null) { entityUpdateMsg = EntityUpdateMsg.newBuilder()
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() .setEntityViewUpdateMsg(entityViewUpdateMsg)
.setEntityViewUpdateMsg(ctx.getEntityViewUpdateMsgConstructor().constructEntityViewUpdatedMsg(msgType, entityView)) .build();
.build(); }
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
@Override
public void onFailure(Throwable t) {
log.warn("Can't processEntityViewCRUD, edgeEvent [{}]", edgeEvent, t);
}
}, ctx.getDbCallbackExecutor());
break; break;
case ENTITY_DELETED_RPC_MESSAGE: case DELETED:
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() case UNASSIGNED_FROM_EDGE:
.setEntityViewUpdateMsg(ctx.getEntityViewUpdateMsgConstructor().constructEntityViewDeleteMsg(entityViewId)) EntityViewUpdateMsg entityViewUpdateMsg =
ctx.getEntityViewUpdateMsgConstructor().constructEntityViewDeleteMsg(entityViewId);
entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setEntityViewUpdateMsg(entityViewUpdateMsg)
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
break; break;
} }
if (entityUpdateMsg != null) {
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
} }
private void processDashboardCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { private void processDashboard(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
DashboardId dashboardId = new DashboardId(edgeEvent.getEntityId()); DashboardId dashboardId = new DashboardId(edgeEvent.getEntityId());
switch (msgType) { EntityUpdateMsg entityUpdateMsg = null;
case ENTITY_CREATED_RPC_MESSAGE: switch (edgeEventAction) {
case ENTITY_UPDATED_RPC_MESSAGE: case ADDED:
case DEVICE_CONFLICT_RPC_MESSAGE: case UPDATED:
ListenableFuture<Dashboard> dashboardFuture = ctx.getDashboardService().findDashboardByIdAsync(edgeEvent.getTenantId(), dashboardId); case ASSIGNED_TO_EDGE:
Futures.addCallback(dashboardFuture, Dashboard dashboard = ctx.getDashboardService().findDashboardById(edgeEvent.getTenantId(), dashboardId);
new FutureCallback<Dashboard>() { if (dashboard != null) {
@Override DashboardUpdateMsg dashboardUpdateMsg =
public void onSuccess(@Nullable Dashboard dashboard) { ctx.getDashboardUpdateMsgConstructor().constructDashboardUpdatedMsg(msgType, dashboard);
if (dashboard != null) { entityUpdateMsg = EntityUpdateMsg.newBuilder()
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() .setDashboardUpdateMsg(dashboardUpdateMsg)
.setDashboardUpdateMsg(ctx.getDashboardUpdateMsgConstructor().constructDashboardUpdatedMsg(msgType, dashboard)) .build();
.build(); }
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
@Override
public void onFailure(Throwable t) {
log.warn("Can't processDashboardCRUD, edgeEvent [{}]", edgeEvent, t);
}
}, ctx.getDbCallbackExecutor());
break; break;
case ENTITY_DELETED_RPC_MESSAGE: case DELETED:
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() case UNASSIGNED_FROM_EDGE:
.setDashboardUpdateMsg(ctx.getDashboardUpdateMsgConstructor().constructDashboardDeleteMsg(dashboardId)) DashboardUpdateMsg dashboardUpdateMsg =
ctx.getDashboardUpdateMsgConstructor().constructDashboardDeleteMsg(dashboardId);
entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setDashboardUpdateMsg(dashboardUpdateMsg)
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
break; break;
} }
if (entityUpdateMsg != null) {
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
} }
private void processRuleChainCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { private void processRuleChain(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId()); RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId());
switch (msgType) { EntityUpdateMsg entityUpdateMsg = null;
case ENTITY_CREATED_RPC_MESSAGE: switch (edgeEventAction) {
case ENTITY_UPDATED_RPC_MESSAGE: case ADDED:
case DEVICE_CONFLICT_RPC_MESSAGE: case UPDATED:
ListenableFuture<RuleChain> ruleChainFuture = ctx.getRuleChainService().findRuleChainByIdAsync(edgeEvent.getTenantId(), ruleChainId); case ASSIGNED_TO_EDGE:
Futures.addCallback(ruleChainFuture, RuleChain ruleChain = ctx.getRuleChainService().findRuleChainById(edgeEvent.getTenantId(), ruleChainId);
new FutureCallback<RuleChain>() { if (ruleChain != null) {
@Override RuleChainUpdateMsg ruleChainUpdateMsg =
public void onSuccess(@Nullable RuleChain ruleChain) { ctx.getRuleChainUpdateMsgConstructor().constructRuleChainUpdatedMsg(edge.getRootRuleChainId(), msgType, ruleChain);
if (ruleChain != null) { entityUpdateMsg = EntityUpdateMsg.newBuilder()
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() .setRuleChainUpdateMsg(ruleChainUpdateMsg)
.setRuleChainUpdateMsg(ctx.getRuleChainUpdateMsgConstructor().constructRuleChainUpdatedMsg(edge.getRootRuleChainId(), msgType, ruleChain)) .build();
.build(); }
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
@Override
public void onFailure(Throwable t) {
log.warn("Can't processRuleChainCRUD, edgeEvent [{}]", edgeEvent, t);
}
}, ctx.getDbCallbackExecutor());
break; break;
case ENTITY_DELETED_RPC_MESSAGE: case DELETED:
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() case UNASSIGNED_FROM_EDGE:
entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setRuleChainUpdateMsg(ctx.getRuleChainUpdateMsgConstructor().constructRuleChainDeleteMsg(ruleChainId)) .setRuleChainUpdateMsg(ctx.getRuleChainUpdateMsgConstructor().constructRuleChainDeleteMsg(ruleChainId))
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
break; break;
} }
if (entityUpdateMsg != null) {
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
} }
private void processRuleChainMetadataCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { private void processRuleChainMetadata(EdgeEvent edgeEvent, UpdateMsgType msgType) {
RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId()); RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId());
ListenableFuture<RuleChain> ruleChainFuture = ctx.getRuleChainService().findRuleChainByIdAsync(edgeEvent.getTenantId(), ruleChainId); RuleChain ruleChain = ctx.getRuleChainService().findRuleChainById(edgeEvent.getTenantId(), ruleChainId);
Futures.addCallback(ruleChainFuture, if (ruleChain != null) {
new FutureCallback<RuleChain>() { RuleChainMetaData ruleChainMetaData = ctx.getRuleChainService().loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId);
@Override RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg =
public void onSuccess(@Nullable RuleChain ruleChain) { ctx.getRuleChainUpdateMsgConstructor().constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData);
if (ruleChain != null) { if (ruleChainMetadataUpdateMsg != null) {
RuleChainMetaData ruleChainMetaData = ctx.getRuleChainService().loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId); EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = .setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg)
ctx.getRuleChainUpdateMsgConstructor().constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData); .build();
if (ruleChainMetadataUpdateMsg != null) { outputStream.onNext(ResponseMsg.newBuilder()
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() .setEntityUpdateMsg(entityUpdateMsg)
.setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg) .build());
.build(); }
outputStream.onNext(ResponseMsg.newBuilder() }
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
}
@Override
public void onFailure(Throwable t) {
log.warn("Can't processRuleChainMetadataCRUD, edgeEvent [{}]", edgeEvent, t);
}
}, ctx.getDbCallbackExecutor());
} }
private void processUserCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { private void processUser(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeActionType) {
UserId userId = new UserId(edgeEvent.getEntityId()); UserId userId = new UserId(edgeEvent.getEntityId());
switch (msgType) { EntityUpdateMsg entityUpdateMsg = null;
case ENTITY_CREATED_RPC_MESSAGE: switch (edgeActionType) {
case ENTITY_UPDATED_RPC_MESSAGE: case ADDED:
case DEVICE_CONFLICT_RPC_MESSAGE: case UPDATED:
ListenableFuture<User> userFuture = ctx.getUserService().findUserByIdAsync(edgeEvent.getTenantId(), userId); case ASSIGNED_TO_EDGE:
Futures.addCallback(userFuture, User user = ctx.getUserService().findUserById(edgeEvent.getTenantId(), userId);
new FutureCallback<User>() { if (user != null) {
@Override entityUpdateMsg = EntityUpdateMsg.newBuilder()
public void onSuccess(@Nullable User user) { .setUserUpdateMsg(ctx.getUserUpdateMsgConstructor().constructUserUpdatedMsg(msgType, user))
if (user != null) { .build();
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() }
.setUserUpdateMsg(ctx.getUserUpdateMsgConstructor().constructUserUpdatedMsg(msgType, user))
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
@Override
public void onFailure(Throwable t) {
log.warn("Can't processUserCRUD, edgeEvent [{}]", edgeEvent, t);
}
}, ctx.getDbCallbackExecutor());
break; break;
case ENTITY_DELETED_RPC_MESSAGE: case DELETED:
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() case UNASSIGNED_FROM_EDGE:
entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setUserUpdateMsg(ctx.getUserUpdateMsgConstructor().constructUserDeleteMsg(userId)) .setUserUpdateMsg(ctx.getUserUpdateMsgConstructor().constructUserDeleteMsg(userId))
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
break; break;
case CREDENTIALS_UPDATED:
UserCredentials userCredentialsByUserId = ctx.getUserService().findUserCredentialsByUserId(edge.getTenantId(), userId);
if (userCredentialsByUserId != null) {
UserCredentialsUpdateMsg userCredentialsUpdateMsg =
ctx.getUserUpdateMsgConstructor().constructUserCredentialsUpdatedMsg(userCredentialsByUserId);
entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setUserCredentialsUpdateMsg(userCredentialsUpdateMsg)
.build();
}
}
if (entityUpdateMsg != null) {
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
} }
} }
private void processRelationCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { private void processRelation(EdgeEvent edgeEvent, UpdateMsgType msgType) {
EntityRelation entityRelation = objectMapper.convertValue(edgeEvent.getEntityBody(), EntityRelation.class); EntityRelation entityRelation = mapper.convertValue(edgeEvent.getEntityBody(), EntityRelation.class);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setRelationUpdateMsg(ctx.getRelationUpdateMsgConstructor().constructRelationUpdatedMsg(msgType, entityRelation)) .setRelationUpdateMsg(ctx.getRelationUpdateMsgConstructor().constructRelationUpdatedMsg(msgType, entityRelation))
.build(); .build();
@ -626,33 +571,27 @@ public final class EdgeGrpcSession implements Closeable {
.build()); .build());
} }
private void processAlarmCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { private void processAlarm(EdgeEvent edgeEvent, UpdateMsgType msgType) {
AlarmId alarmId = new AlarmId(edgeEvent.getEntityId()); try {
ListenableFuture<Alarm> alarmFuture = ctx.getAlarmService().findAlarmByIdAsync(edgeEvent.getTenantId(), alarmId); AlarmId alarmId = new AlarmId(edgeEvent.getEntityId());
Futures.addCallback(alarmFuture, Alarm alarm = ctx.getAlarmService().findAlarmByIdAsync(edgeEvent.getTenantId(), alarmId).get();
new FutureCallback<Alarm>() { if (alarm != null) {
@Override EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
public void onSuccess(@Nullable Alarm alarm) { .setAlarmUpdateMsg(ctx.getAlarmUpdateMsgConstructor().constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm))
if (alarm != null) { .build();
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() outputStream.onNext(ResponseMsg.newBuilder()
.setAlarmUpdateMsg(ctx.getAlarmUpdateMsgConstructor().constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm)) .setEntityUpdateMsg(entityUpdateMsg)
.build(); .build());
outputStream.onNext(ResponseMsg.newBuilder() }
.setEntityUpdateMsg(entityUpdateMsg) } catch (Exception e) {
.build()); log.error("Can't process alarm msg [{}] [{}]", edgeEvent, msgType, e);
} }
}
@Override
public void onFailure(Throwable t) {
log.warn("Can't processAlarmCRUD, edgeEvent [{}]", edgeEvent, t);
}
}, ctx.getDbCallbackExecutor());
} }
private UpdateMsgType getResponseMsgType(ActionType actionType) { private UpdateMsgType getResponseMsgType(ActionType actionType) {
switch (actionType) { switch (actionType) {
case UPDATED: case UPDATED:
case CREDENTIALS_UPDATED:
return UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE; return UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE;
case ADDED: case ADDED:
case ASSIGNED_TO_EDGE: case ASSIGNED_TO_EDGE:
@ -664,10 +603,6 @@ public final class EdgeGrpcSession implements Closeable {
return UpdateMsgType.ALARM_ACK_RPC_MESSAGE; return UpdateMsgType.ALARM_ACK_RPC_MESSAGE;
case ALARM_CLEAR: case ALARM_CLEAR:
return UpdateMsgType.ALARM_CLEAR_RPC_MESSAGE; return UpdateMsgType.ALARM_CLEAR_RPC_MESSAGE;
case ATTRIBUTES_UPDATED:
case ATTRIBUTES_DELETED:
case TIMESERIES_DELETED:
return null;
default: default:
throw new RuntimeException("Unsupported actionType [" + actionType + "]"); throw new RuntimeException("Unsupported actionType [" + actionType + "]");
} }
@ -702,11 +637,17 @@ public final class EdgeGrpcSession implements Closeable {
} }
} }
} }
if (uplinkMsg.getDeviceUpdateMsgList() != null && !uplinkMsg.getDeviceUpdateMsgList().isEmpty()) { if (uplinkMsg.getDeviceUpdateMsgList() != null && !uplinkMsg.getDeviceUpdateMsgList().isEmpty()) {
for (DeviceUpdateMsg deviceUpdateMsg : uplinkMsg.getDeviceUpdateMsgList()) { for (DeviceUpdateMsg deviceUpdateMsg : uplinkMsg.getDeviceUpdateMsgList()) {
onDeviceUpdate(deviceUpdateMsg); onDeviceUpdate(deviceUpdateMsg);
} }
} }
if (uplinkMsg.getDeviceCredentialsUpdateMsgList() != null && !uplinkMsg.getDeviceCredentialsUpdateMsgList().isEmpty()) {
for (DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg : uplinkMsg.getDeviceCredentialsUpdateMsgList()) {
onDeviceCredentialsUpdate(deviceCredentialsUpdateMsg);
}
}
if (uplinkMsg.getAlarmUpdateMsgList() != null && !uplinkMsg.getAlarmUpdateMsgList().isEmpty()) { if (uplinkMsg.getAlarmUpdateMsgList() != null && !uplinkMsg.getAlarmUpdateMsgList().isEmpty()) {
for (AlarmUpdateMsg alarmUpdateMsg : uplinkMsg.getAlarmUpdateMsgList()) { for (AlarmUpdateMsg alarmUpdateMsg : uplinkMsg.getAlarmUpdateMsgList()) {
onAlarmUpdate(alarmUpdateMsg); onAlarmUpdate(alarmUpdateMsg);
@ -714,7 +655,27 @@ public final class EdgeGrpcSession implements Closeable {
} }
if (uplinkMsg.getRuleChainMetadataRequestMsgList() != null && !uplinkMsg.getRuleChainMetadataRequestMsgList().isEmpty()) { if (uplinkMsg.getRuleChainMetadataRequestMsgList() != null && !uplinkMsg.getRuleChainMetadataRequestMsgList().isEmpty()) {
for (RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg : uplinkMsg.getRuleChainMetadataRequestMsgList()) { for (RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg : uplinkMsg.getRuleChainMetadataRequestMsgList()) {
ctx.getSyncEdgeService().syncRuleChainMetadata(edge, ruleChainMetadataRequestMsg, outputStream); ctx.getSyncEdgeService().processRuleChainMetadataRequestMsg(edge, ruleChainMetadataRequestMsg);
}
}
if (uplinkMsg.getAttributesRequestMsgList() != null && !uplinkMsg.getAttributesRequestMsgList().isEmpty()) {
for (AttributesRequestMsg attributesRequestMsg : uplinkMsg.getAttributesRequestMsgList()) {
ctx.getSyncEdgeService().processAttributesRequestMsg(edge, attributesRequestMsg);
}
}
if (uplinkMsg.getRelationRequestMsgList() != null && !uplinkMsg.getRelationRequestMsgList().isEmpty()) {
for (RelationRequestMsg relationRequestMsg : uplinkMsg.getRelationRequestMsgList()) {
ctx.getSyncEdgeService().processRelationRequestMsg(edge, relationRequestMsg);
}
}
if (uplinkMsg.getUserCredentialsRequestMsgList() != null && !uplinkMsg.getUserCredentialsRequestMsgList().isEmpty()) {
for (UserCredentialsRequestMsg userCredentialsRequestMsg : uplinkMsg.getUserCredentialsRequestMsgList()) {
ctx.getSyncEdgeService().processUserCredentialsRequestMsg(edge, userCredentialsRequestMsg);
}
}
if (uplinkMsg.getDeviceCredentialsRequestMsgList() != null && !uplinkMsg.getDeviceCredentialsRequestMsgList().isEmpty()) {
for (DeviceCredentialsRequestMsg deviceCredentialsRequestMsg : uplinkMsg.getDeviceCredentialsRequestMsgList()) {
ctx.getSyncEdgeService().processDeviceCredentialsRequestMsg(edge, deviceCredentialsRequestMsg);
} }
} }
} catch (Exception e) { } catch (Exception e) {
@ -817,17 +778,19 @@ public final class EdgeGrpcSession implements Closeable {
Device deviceById = ctx.getDeviceService().findDeviceById(edge.getTenantId(), edgeDeviceId); Device deviceById = ctx.getDeviceService().findDeviceById(edge.getTenantId(), edgeDeviceId);
if (deviceById != null) { if (deviceById != null) {
// this ID already used by other device - create new device and update ID on the edge // this ID already used by other device - create new device and update ID on the edge
Device savedDevice = createDevice(deviceUpdateMsg); device = createDevice(deviceUpdateMsg);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setDeviceUpdateMsg(ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(UpdateMsgType.DEVICE_CONFLICT_RPC_MESSAGE, savedDevice)) .setDeviceUpdateMsg(ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(UpdateMsgType.DEVICE_CONFLICT_RPC_MESSAGE, device))
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder() outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg) .setEntityUpdateMsg(entityUpdateMsg)
.build()); .build());
} else { } else {
createDevice(deviceUpdateMsg); device = createDevice(deviceUpdateMsg);
} }
} }
// TODO: voba - assign device only in case device is not assigned yet. Missing functionality to check this relation prior assignment
ctx.getDeviceService().assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId());
break; break;
case ENTITY_UPDATED_RPC_MESSAGE: case ENTITY_UPDATED_RPC_MESSAGE:
updateDevice(deviceUpdateMsg); updateDevice(deviceUpdateMsg);
@ -850,21 +813,57 @@ public final class EdgeGrpcSession implements Closeable {
device.setType(deviceUpdateMsg.getType()); device.setType(deviceUpdateMsg.getType());
device.setLabel(deviceUpdateMsg.getLabel()); device.setLabel(deviceUpdateMsg.getLabel());
device = ctx.getDeviceService().saveDevice(device); device = ctx.getDeviceService().saveDevice(device);
updateDeviceCredentials(deviceUpdateMsg, device);
requestDeviceCredentialsFromEdge(device);
} }
private void updateDeviceCredentials(DeviceUpdateMsg deviceUpdateMsg, Device device) { private void onDeviceCredentialsUpdate(DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg) {
log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]", log.debug("Executing onDeviceCredentialsUpdate, deviceCredentialsUpdateMsg [{}]", deviceCredentialsUpdateMsg);
device.getName(), deviceUpdateMsg.getCredentialsId(), deviceUpdateMsg.getCredentialsValue()); DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsUpdateMsg.getDeviceIdMSB(), deviceCredentialsUpdateMsg.getDeviceIdLSB()));
ListenableFuture<Device> deviceFuture = ctx.getDeviceService().findDeviceByIdAsync(edge.getTenantId(), deviceId);
DeviceCredentials deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(edge.getTenantId(), device.getId()); Futures.addCallback(deviceFuture, new FutureCallback<Device>() {
deviceCredentials.setCredentialsType(DeviceCredentialsType.valueOf(deviceUpdateMsg.getCredentialsType())); @Override
deviceCredentials.setCredentialsId(deviceUpdateMsg.getCredentialsId()); public void onSuccess(@Nullable Device device) {
deviceCredentials.setCredentialsValue(deviceUpdateMsg.getCredentialsValue()); if (device != null) {
ctx.getDeviceCredentialsService().updateDeviceCredentials(edge.getTenantId(), deviceCredentials); log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]",
log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]", device.getName(), deviceCredentialsUpdateMsg.getCredentialsId(), deviceCredentialsUpdateMsg.getCredentialsValue());
device.getName(), deviceUpdateMsg.getCredentialsId(), deviceUpdateMsg.getCredentialsValue()); try {
DeviceCredentials deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(edge.getTenantId(), device.getId());
deviceCredentials.setCredentialsType(DeviceCredentialsType.valueOf(deviceCredentialsUpdateMsg.getCredentialsType()));
deviceCredentials.setCredentialsId(deviceCredentialsUpdateMsg.getCredentialsId());
deviceCredentials.setCredentialsValue(deviceCredentialsUpdateMsg.getCredentialsValue());
ctx.getDeviceCredentialsService().updateDeviceCredentials(edge.getTenantId(), deviceCredentials);
} catch (Exception e) {
log.error("Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]", device.getName(), deviceCredentialsUpdateMsg, e);
}
}
}
@Override
public void onFailure(Throwable t) {
log.error("Can't update device credentials for deviceCredentialsUpdateMsg [{}]", deviceCredentialsUpdateMsg, t);
}
}, ctx.getDbCallbackExecutor());
}
private void requestDeviceCredentialsFromEdge(Device device) {
log.debug("Executing requestDeviceCredentialsFromEdge device [{}]", device);
DownlinkMsg downlinkMsg = constructDeviceCredentialsRequestMsg(device.getId());
outputStream.onNext(ResponseMsg.newBuilder()
.setDownlinkMsg(downlinkMsg)
.build());
}
private DownlinkMsg constructDeviceCredentialsRequestMsg(DeviceId deviceId) {
DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = DeviceCredentialsRequestMsg.newBuilder()
.setDeviceIdMSB(deviceId.getId().getMostSignificantBits())
.setDeviceIdLSB(deviceId.getId().getLeastSignificantBits())
.build();
DownlinkMsg.Builder builder = DownlinkMsg.newBuilder()
.addAllDeviceCredentialsRequestMsg(Collections.singletonList(deviceCredentialsRequestMsg));
return builder.build();
} }
private Device createDevice(DeviceUpdateMsg deviceUpdateMsg) { private Device createDevice(DeviceUpdateMsg deviceUpdateMsg) {
@ -880,17 +879,68 @@ public final class EdgeGrpcSession implements Closeable {
device.setType(deviceUpdateMsg.getType()); device.setType(deviceUpdateMsg.getType());
device.setLabel(deviceUpdateMsg.getLabel()); device.setLabel(deviceUpdateMsg.getLabel());
device = ctx.getDeviceService().saveDevice(device); device = ctx.getDeviceService().saveDevice(device);
device = ctx.getDeviceService().assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId()); createDeviceCredentials(device);
createRelationFromEdge(device.getId()); createRelationFromEdge(device.getId());
ctx.getRelationService().saveRelationAsync(TenantId.SYS_TENANT_ID, new EntityRelation(edge.getId(), device.getId(), "Created"));
ctx.getDeviceStateService().onDeviceAdded(device); ctx.getDeviceStateService().onDeviceAdded(device);
updateDeviceCredentials(deviceUpdateMsg, device); pushDeviceCreatedEventToRuleEngine(device);
requestDeviceCredentialsFromEdge(device);
} finally { } finally {
deviceCreationLock.unlock(); deviceCreationLock.unlock();
} }
return device; return device;
} }
private void createDeviceCredentials(Device device) {
DeviceCredentials deviceCredentials = new DeviceCredentials();
deviceCredentials.setDeviceId(device.getId());
deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
deviceCredentials.setCredentialsId(RandomStringUtils.randomAlphanumeric(20));
ctx.getDeviceCredentialsService().createDeviceCredentials(device.getTenantId(), deviceCredentials);
}
private void pushDeviceCreatedEventToRuleEngine(Device device) {
try {
ObjectNode entityNode = mapper.valueToTree(device);
TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, device.getId(), getActionTbMsgMetaData(device.getCustomerId()), mapper.writeValueAsString(entityNode));
sendToRuleEngine(edge.getTenantId(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
// TODO: voba - handle success
}
@Override
public void onFailure(Throwable t) {
// TODO: voba - handle failure
}
});
} catch (JsonProcessingException | IllegalArgumentException e) {
log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), DataConstants.ENTITY_CREATED, e);
}
}
protected void sendToRuleEngine(TenantId tenantId, TbMsg tbMsg, TbQueueCallback callback) {
TopicPartitionInfo tpi = ctx.getPartitionService().resolve(ServiceType.TB_RULE_ENGINE, tenantId, tbMsg.getOriginator());
TransportProtos.ToRuleEngineMsg msg = TransportProtos.ToRuleEngineMsg.newBuilder().setTbMsg(TbMsg.toByteString(tbMsg))
.setTenantIdMSB(tenantId.getId().getMostSignificantBits())
.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()).build();
ruleEngineMsgProducer.send(tpi, new TbProtoQueueMsg<>(tbMsg.getId(), msg), callback);
}
private TbMsgMetaData getActionTbMsgMetaData(CustomerId customerId) {
TbMsgMetaData metaData = getTbMsgMetaData(edge);
if (customerId != null && !customerId.isNullUid()) {
metaData.putValue("customerId", customerId.toString());
}
return metaData;
}
private TbMsgMetaData getTbMsgMetaData(Edge edge) {
TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue("edgeId", edge.getId().toString());
metaData.putValue("edgeName", edge.getName());
return metaData;
}
private EntityId getAlarmOriginator(String entityName, org.thingsboard.server.common.data.EntityType entityType) { private EntityId getAlarmOriginator(String entityName, org.thingsboard.server.common.data.EntityType entityType) {
switch (entityType) { switch (entityType) {
case DEVICE: case DEVICE:
@ -925,7 +975,7 @@ public final class EdgeGrpcSession implements Closeable {
existentAlarm.setPropagate(alarmUpdateMsg.getPropagate()); existentAlarm.setPropagate(alarmUpdateMsg.getPropagate());
} }
existentAlarm.setEndTs(alarmUpdateMsg.getEndTs()); existentAlarm.setEndTs(alarmUpdateMsg.getEndTs());
existentAlarm.setDetails(objectMapper.readTree(alarmUpdateMsg.getDetails())); existentAlarm.setDetails(mapper.readTree(alarmUpdateMsg.getDetails()));
ctx.getAlarmService().createOrUpdateAlarm(existentAlarm); ctx.getAlarmService().createOrUpdateAlarm(existentAlarm);
break; break;
case ALARM_ACK_RPC_MESSAGE: case ALARM_ACK_RPC_MESSAGE:
@ -935,7 +985,7 @@ public final class EdgeGrpcSession implements Closeable {
break; break;
case ALARM_CLEAR_RPC_MESSAGE: case ALARM_CLEAR_RPC_MESSAGE:
if (existentAlarm != null) { if (existentAlarm != null) {
ctx.getAlarmService().clearAlarm(edge.getTenantId(), existentAlarm.getId(), objectMapper.readTree(alarmUpdateMsg.getDetails()), alarmUpdateMsg.getAckTs()); ctx.getAlarmService().clearAlarm(edge.getTenantId(), existentAlarm.getId(), mapper.readTree(alarmUpdateMsg.getDetails()), alarmUpdateMsg.getAckTs());
} }
break; break;
case ENTITY_DELETED_RPC_MESSAGE: case ENTITY_DELETED_RPC_MESSAGE:

6
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardUpdateMsgConstructor.java

@ -16,11 +16,9 @@
package org.thingsboard.server.service.edge.rpc.constructor; package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.util.mapping.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.DashboardUpdateMsg; import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType; import org.thingsboard.server.gen.edge.UpdateMsgType;
@ -29,11 +27,7 @@ import org.thingsboard.server.gen.edge.UpdateMsgType;
@Slf4j @Slf4j
public class DashboardUpdateMsgConstructor { public class DashboardUpdateMsgConstructor {
@Autowired
private DashboardService dashboardService;
public DashboardUpdateMsg constructDashboardUpdatedMsg(UpdateMsgType msgType, Dashboard dashboard) { public DashboardUpdateMsg constructDashboardUpdatedMsg(UpdateMsgType msgType, Dashboard dashboard) {
dashboard = dashboardService.findDashboardById(dashboard.getTenantId(), dashboard.getId());
DashboardUpdateMsg.Builder builder = DashboardUpdateMsg.newBuilder() DashboardUpdateMsg.Builder builder = DashboardUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
.setIdMSB(dashboard.getId().getId().getMostSignificantBits()) .setIdMSB(dashboard.getId().getId().getMostSignificantBits())

33
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceUpdateMsgConstructor.java

@ -16,12 +16,11 @@
package org.thingsboard.server.service.edge.rpc.constructor; package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType; import org.thingsboard.server.gen.edge.UpdateMsgType;
@ -29,9 +28,6 @@ import org.thingsboard.server.gen.edge.UpdateMsgType;
@Slf4j @Slf4j
public class DeviceUpdateMsgConstructor { public class DeviceUpdateMsgConstructor {
@Autowired
private DeviceCredentialsService deviceCredentialsService;
public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device) { public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device) {
DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder() DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
@ -42,20 +38,19 @@ public class DeviceUpdateMsgConstructor {
if (device.getLabel() != null) { if (device.getLabel() != null) {
builder.setLabel(device.getLabel()); builder.setLabel(device.getLabel());
} }
if (msgType.equals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE) || return builder.build();
msgType.equals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE) || }
msgType.equals(UpdateMsgType.DEVICE_CONFLICT_RPC_MESSAGE)) {
DeviceCredentials deviceCredentials public DeviceCredentialsUpdateMsg constructDeviceCredentialsUpdatedMsg(DeviceCredentials deviceCredentials) {
= deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), device.getId()); DeviceCredentialsUpdateMsg.Builder builder = DeviceCredentialsUpdateMsg.newBuilder()
if (deviceCredentials != null) { .setDeviceIdMSB(deviceCredentials.getDeviceId().getId().getMostSignificantBits())
if (deviceCredentials.getCredentialsType() != null) { .setDeviceIdLSB(deviceCredentials.getDeviceId().getId().getLeastSignificantBits());
builder.setCredentialsType(deviceCredentials.getCredentialsType().name()) if (deviceCredentials.getCredentialsType() != null) {
.setCredentialsId(deviceCredentials.getCredentialsId()); builder.setCredentialsType(deviceCredentials.getCredentialsType().name())
} .setCredentialsId(deviceCredentials.getCredentialsId());
if (deviceCredentials.getCredentialsValue() != null) { }
builder.setCredentialsValue(deviceCredentials.getCredentialsValue()); if (deviceCredentials.getCredentialsValue() != null) {
} builder.setCredentialsValue(deviceCredentials.getCredentialsValue());
}
} }
return builder.build(); return builder.build();
} }

25
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/UserUpdateMsgConstructor.java

@ -16,31 +16,26 @@
package org.thingsboard.server.service.edge.rpc.constructor; package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.dao.util.mapping.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.UpdateMsgType; import org.thingsboard.server.gen.edge.UpdateMsgType;
import org.thingsboard.server.gen.edge.UserCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.UserUpdateMsg; import org.thingsboard.server.gen.edge.UserUpdateMsg;
@Component @Component
@Slf4j @Slf4j
public class UserUpdateMsgConstructor { public class UserUpdateMsgConstructor {
@Autowired
private UserService userService;
public UserUpdateMsg constructUserUpdatedMsg(UpdateMsgType msgType, User user) { public UserUpdateMsg constructUserUpdatedMsg(UpdateMsgType msgType, User user) {
UserUpdateMsg.Builder builder = UserUpdateMsg.newBuilder() UserUpdateMsg.Builder builder = UserUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
.setIdMSB(user.getId().getId().getMostSignificantBits()) .setIdMSB(user.getId().getId().getMostSignificantBits())
.setIdLSB(user.getId().getId().getLeastSignificantBits()) .setIdLSB(user.getId().getId().getLeastSignificantBits())
.setEmail(user.getEmail()) .setEmail(user.getEmail())
.setAuthority(user.getAuthority().name()) .setAuthority(user.getAuthority().name());
.setEnabled(false);
if (user.getFirstName() != null) { if (user.getFirstName() != null) {
builder.setFirstName(user.getFirstName()); builder.setFirstName(user.getFirstName());
} }
@ -53,13 +48,6 @@ public class UserUpdateMsgConstructor {
if (user.getAdditionalInfo() != null) { if (user.getAdditionalInfo() != null) {
builder.setAdditionalInfo(JacksonUtil.toString(user.getAdditionalInfo())); builder.setAdditionalInfo(JacksonUtil.toString(user.getAdditionalInfo()));
} }
if (msgType.equals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE) ||
msgType.equals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE)) {
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
if (userCredentials != null) {
builder.setEnabled(userCredentials.isEnabled()).setPassword(userCredentials.getPassword());
}
}
return builder.build(); return builder.build();
} }
@ -69,4 +57,13 @@ public class UserUpdateMsgConstructor {
.setIdMSB(userId.getId().getMostSignificantBits()) .setIdMSB(userId.getId().getMostSignificantBits())
.setIdLSB(userId.getId().getLeastSignificantBits()).build(); .setIdLSB(userId.getId().getLeastSignificantBits()).build();
} }
public UserCredentialsUpdateMsg constructUserCredentialsUpdatedMsg(UserCredentials userCredentials) {
UserCredentialsUpdateMsg.Builder builder = UserCredentialsUpdateMsg.newBuilder()
.setUserIdMSB(userCredentials.getUserId().getId().getMostSignificantBits())
.setUserIdLSB(userCredentials.getUserId().getId().getLeastSignificantBits())
.setEnabled(userCredentials.isEnabled())
.setPassword(userCredentials.getPassword());
return builder.build();
}
} }

481
application/src/main/java/org/thingsboard/server/service/edge/rpc/init/DefaultSyncEdgeService.java

@ -15,22 +15,36 @@
*/ */
package org.thingsboard.server.service.edge.rpc.init; package org.thingsboard.server.service.edge.rpc.init;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.DataType;
import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageData; import org.thingsboard.server.common.data.page.TimePageData;
@ -40,45 +54,38 @@ import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.gen.edge.AssetUpdateMsg; import org.thingsboard.server.gen.edge.AttributesRequestMsg;
import org.thingsboard.server.gen.edge.DashboardUpdateMsg; import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.RelationRequestMsg;
import org.thingsboard.server.gen.edge.EntityUpdateMsg;
import org.thingsboard.server.gen.edge.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.RelationUpdateMsg;
import org.thingsboard.server.gen.edge.ResponseMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg; import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.RuleChainUpdateMsg; import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.gen.edge.UpdateMsgType;
import org.thingsboard.server.gen.edge.UserUpdateMsg;
import org.thingsboard.server.service.edge.EdgeContextComponent;
import org.thingsboard.server.service.edge.rpc.constructor.AssetUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DashboardUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DeviceUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.RelationUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.UserUpdateMsgConstructor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
@Service @Service
@Slf4j @Slf4j
public class DefaultSyncEdgeService implements SyncEdgeService { public class DefaultSyncEdgeService implements SyncEdgeService {
private static final ObjectMapper mapper = new ObjectMapper();
@Autowired
private EdgeEventService edgeEventService;
@Autowired
private AttributesService attributesService;
@Autowired @Autowired
private RuleChainService ruleChainService; private RuleChainService ruleChainService;
@ -101,299 +108,323 @@ public class DefaultSyncEdgeService implements SyncEdgeService {
private UserService userService; private UserService userService;
@Autowired @Autowired
private RuleChainUpdateMsgConstructor ruleChainUpdateMsgConstructor; private DbCallbackExecutorService dbCallbackExecutorService;
@Autowired
private DeviceUpdateMsgConstructor deviceUpdateMsgConstructor;
@Autowired
private AssetUpdateMsgConstructor assetUpdateMsgConstructor;
@Autowired
private EntityViewUpdateMsgConstructor entityViewUpdateMsgConstructor;
@Autowired
private DashboardUpdateMsgConstructor dashboardUpdateMsgConstructor;
@Autowired
private UserUpdateMsgConstructor userUpdateMsgConstructor;
@Autowired
private RelationUpdateMsgConstructor relationUpdateMsgConstructor;
@Override @Override
public void sync(EdgeContextComponent ctx, Edge edge, StreamObserver<ResponseMsg> outputStream) { public void sync(Edge edge) {
Set<EntityId> pushedEntityIds = new HashSet<>(); try {
syncUsers(ctx, edge, pushedEntityIds, outputStream); syncUsers(edge);
List<ListenableFuture<Void>> futures = new ArrayList<>(); syncRuleChains(edge);
futures.add(syncRuleChains(ctx, edge, pushedEntityIds, outputStream)); syncDevices(edge);
futures.add(syncDevices(ctx, edge, pushedEntityIds, outputStream)); syncAssets(edge);
futures.add(syncAssets(ctx, edge, pushedEntityIds, outputStream)); syncEntityViews(edge);
futures.add(syncEntityViews(ctx, edge, pushedEntityIds, outputStream)); syncDashboards(edge);
futures.add(syncDashboards(ctx, edge, pushedEntityIds, outputStream)); } catch (Exception e) {
ListenableFuture<List<Void>> joinFuture = Futures.allAsList(futures); log.error("Exception during sync process", e);
Futures.transform(joinFuture, result -> { }
syncRelations(ctx, edge, pushedEntityIds, outputStream);
return null;
}, MoreExecutors.directExecutor());
} }
private ListenableFuture<Void> syncRuleChains(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncRuleChains(Edge edge) {
try { try {
ListenableFuture<TimePageData<RuleChain>> future = ruleChainService.findRuleChainsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE)); ListenableFuture<TimePageData<RuleChain>> future =
return Futures.transform(future, pageData -> { ruleChainService.findRuleChainsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
try { Futures.addCallback(future, new FutureCallback<TimePageData<RuleChain>>() {
@Override
public void onSuccess(@Nullable TimePageData<RuleChain> pageData) {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] rule chains(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] rule chains(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (RuleChain ruleChain : pageData.getData()) { for (RuleChain ruleChain : pageData.getData()) {
RuleChainUpdateMsg ruleChainUpdateMsg = saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.RULE_CHAIN, ActionType.ADDED, ruleChain.getId(), null);
ruleChainUpdateMsgConstructor.constructRuleChainUpdatedMsg(
edge.getRootRuleChainId(),
UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE,
ruleChain);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setRuleChainUpdateMsg(ruleChainUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(ruleChain.getId());
} }
} }
} catch (Exception e) {
log.error("Exception during loading edge rule chain(s) on sync!", e);
} }
return null;
}, ctx.getDbCallbackExecutor()); @Override
public void onFailure(Throwable t) {
log.error("Exception during loading edge rule chain(s) on sync!", t);
}
}, dbCallbackExecutorService);
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge rule chain(s) on sync!", e); log.error("Exception during loading edge rule chain(s) on sync!", e);
return Futures.immediateFuture(null);
} }
} }
private ListenableFuture<Void> syncDevices(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncDevices(Edge edge) {
try { try {
ListenableFuture<TimePageData<Device>> future = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE)); ListenableFuture<TimePageData<Device>> future =
return Futures.transform(future, pageData -> { deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { Futures.addCallback(future, new FutureCallback<TimePageData<Device>>() {
log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); @Override
for (Device device : pageData.getData()) { public void onSuccess(@Nullable TimePageData<Device> pageData) {
DeviceUpdateMsg deviceUpdateMsg = if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
deviceUpdateMsgConstructor.constructDeviceUpdatedMsg( log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, for (Device device : pageData.getData()) {
device); saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.DEVICE, ActionType.ADDED, device.getId(), null);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() }
.setDeviceUpdateMsg(deviceUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(device.getId());
} }
} }
return null;
}, ctx.getDbCallbackExecutor()); @Override
public void onFailure(Throwable t) {
log.error("Exception during loading edge device(s) on sync!", t);
}
}, dbCallbackExecutorService);
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge device(s) on sync!", e); log.error("Exception during loading edge device(s) on sync!", e);
return Futures.immediateFuture(null);
} }
} }
private ListenableFuture<Void> syncAssets(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncAssets(Edge edge) {
try { try {
ListenableFuture<TimePageData<Asset>> future = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE)); ListenableFuture<TimePageData<Asset>> future = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
return Futures.transform(future, pageData -> { Futures.addCallback(future, new FutureCallback<TimePageData<Asset>>() {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { @Override
log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); public void onSuccess(@Nullable TimePageData<Asset> pageData) {
for (Asset asset : pageData.getData()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
AssetUpdateMsg assetUpdateMsg = log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
assetUpdateMsgConstructor.constructAssetUpdatedMsg( for (Asset asset : pageData.getData()) {
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.ASSET, ActionType.ADDED, asset.getId(), null);
asset); }
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setAssetUpdateMsg(assetUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(asset.getId());
} }
} }
return null;
}, ctx.getDbCallbackExecutor()); @Override
public void onFailure(Throwable t) {
log.error("Exception during loading edge asset(s) on sync!", t);
}
}, dbCallbackExecutorService);
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge asset(s) on sync!", e); log.error("Exception during loading edge asset(s) on sync!", e);
return Futures.immediateFuture(null);
} }
} }
private ListenableFuture<Void> syncEntityViews(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncEntityViews(Edge edge) {
try { try {
ListenableFuture<TimePageData<EntityView>> future = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE)); ListenableFuture<TimePageData<EntityView>> future = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
return Futures.transform(future, pageData -> { Futures.addCallback(future, new FutureCallback<TimePageData<EntityView>>() {
try { @Override
public void onSuccess(@Nullable TimePageData<EntityView> pageData) {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (EntityView entityView : pageData.getData()) { for (EntityView entityView : pageData.getData()) {
EntityViewUpdateMsg entityViewUpdateMsg = saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.ENTITY_VIEW, ActionType.ADDED, entityView.getId(), null);
entityViewUpdateMsgConstructor.constructEntityViewUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
entityView);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setEntityViewUpdateMsg(entityViewUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(entityView.getId());
} }
} }
} catch (Exception e) {
log.error("Exception during loading edge entity view(s) on sync!", e);
} }
return null;
}, ctx.getDbCallbackExecutor()); @Override
public void onFailure(Throwable t) {
log.error("Exception during loading edge entity view(s) on sync!", t);
}
}, dbCallbackExecutorService);
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge entity view(s) on sync!", e); log.error("Exception during loading edge entity view(s) on sync!", e);
return Futures.immediateFuture(null);
} }
} }
private ListenableFuture<Void> syncDashboards(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncDashboards(Edge edge) {
try { try {
ListenableFuture<TimePageData<DashboardInfo>> future = dashboardService.findDashboardsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE)); ListenableFuture<TimePageData<DashboardInfo>> future = dashboardService.findDashboardsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
return Futures.transform(future, pageData -> { Futures.addCallback(future, new FutureCallback<TimePageData<DashboardInfo>>() {
try { @Override
public void onSuccess(@Nullable TimePageData<DashboardInfo> pageData) {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] dashboard(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] dashboard(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (DashboardInfo dashboardInfo : pageData.getData()) { for (DashboardInfo dashboardInfo : pageData.getData()) {
Dashboard dashboard = dashboardService.findDashboardById(edge.getTenantId(), dashboardInfo.getId()); saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.DASHBOARD, ActionType.ADDED, dashboardInfo.getId(), null);
DashboardUpdateMsg dashboardUpdateMsg =
dashboardUpdateMsgConstructor.constructDashboardUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
dashboard);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setDashboardUpdateMsg(dashboardUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(dashboard.getId());
} }
} }
} catch (Exception e) {
log.error("Exception during loading edge dashboard(s) on sync!", e);
} }
return null;
}, ctx.getDbCallbackExecutor()); @Override
public void onFailure(Throwable t) {
log.error("Exception during loading edge dashboard(s) on sync!", t);
}
}, dbCallbackExecutorService);
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge dashboard(s) on sync!", e); log.error("Exception during loading edge dashboard(s) on sync!", e);
return Futures.immediateFuture(null);
} }
} }
private void syncUsers(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncUsers(Edge edge) {
try { try {
TextPageData<User> pageData = userService.findTenantAdmins(edge.getTenantId(), new TextPageLink(Integer.MAX_VALUE)); TextPageData<User> pageData = userService.findTenantAdmins(edge.getTenantId(), new TextPageLink(Integer.MAX_VALUE));
pushUsersToEdge(pageData, edge, pushedEntityIds, outputStream); pushUsersToEdge(pageData, edge);
if (edge.getCustomerId() != null && !EntityId.NULL_UUID.equals(edge.getCustomerId().getId())) { if (edge.getCustomerId() != null && !EntityId.NULL_UUID.equals(edge.getCustomerId().getId())) {
pageData = userService.findCustomerUsers(edge.getTenantId(), edge.getCustomerId(), new TextPageLink(Integer.MAX_VALUE)); pageData = userService.findCustomerUsers(edge.getTenantId(), edge.getCustomerId(), new TextPageLink(Integer.MAX_VALUE));
pushUsersToEdge(pageData, edge, pushedEntityIds, outputStream); pushUsersToEdge(pageData, edge);
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge user(s) on sync!", e); log.error("Exception during loading edge user(s) on sync!", e);
} }
} }
private void pushUsersToEdge(TextPageData<User> pageData, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void pushUsersToEdge(TextPageData<User> pageData, Edge edge) {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] user(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] user(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (User user : pageData.getData()) { for (User user : pageData.getData()) {
UserUpdateMsg userUpdateMsg = saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, ActionType.ADDED, user.getId(), null);
userUpdateMsgConstructor.constructUserUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
user);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setUserUpdateMsg(userUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(user.getId());
} }
} }
} }
private ListenableFuture<Void> syncRelations(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { @Override
if (!pushedEntityIds.isEmpty()) { public void processRuleChainMetadataRequestMsg(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg) {
List<ListenableFuture<List<EntityRelation>>> futures = new ArrayList<>(); if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) {
for (EntityId entityId : pushedEntityIds) { RuleChainId ruleChainId = new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB()));
futures.add(syncRelations(edge, entityId, EntitySearchDirection.FROM)); saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.RULE_CHAIN_METADATA, ActionType.ADDED, ruleChainId, null);
futures.add(syncRelations(edge, entityId, EntitySearchDirection.TO)); }
} }
ListenableFuture<List<List<EntityRelation>>> relationsListFuture = Futures.allAsList(futures);
return Futures.transform(relationsListFuture, relationsList -> { @Override
try { public void processAttributesRequestMsg(Edge edge, AttributesRequestMsg attributesRequestMsg) {
Set<EntityRelation> uniqueEntityRelations = new HashSet<>(); EntityId entityId = EntityIdFactory.getByTypeAndUuid(
if (!relationsList.isEmpty()) { EntityType.valueOf(attributesRequestMsg.getEntityType()),
for (List<EntityRelation> entityRelations : relationsList) { new UUID(attributesRequestMsg.getEntityIdMSB(), attributesRequestMsg.getEntityIdLSB()));
if (!entityRelations.isEmpty()) { final EdgeEventType edgeEventType = getEdgeQueueTypeByEntityType(entityId.getEntityType());
uniqueEntityRelations.addAll(entityRelations); if (edgeEventType != null) {
ListenableFuture<List<AttributeKvEntry>> ssAttrFuture = attributesService.findAll(edge.getTenantId(), entityId, DataConstants.SERVER_SCOPE);
Futures.addCallback(ssAttrFuture, new FutureCallback<List<AttributeKvEntry>>() {
@Override
public void onSuccess(@Nullable List<AttributeKvEntry> ssAttributes) {
if (ssAttributes != null && !ssAttributes.isEmpty()) {
try {
ObjectNode entityNode = mapper.createObjectNode();
for (AttributeKvEntry attr : ssAttributes) {
if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) {
entityNode.put(attr.getKey(), attr.getBooleanValue().get());
} else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) {
entityNode.put(attr.getKey(), attr.getDoubleValue().get());
} else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) {
entityNode.put(attr.getKey(), attr.getLongValue().get());
} else {
entityNode.put(attr.getKey(), attr.getValueAsString());
}
} }
log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, entityNode);
saveEdgeEvent(edge.getTenantId(),
edge.getId(),
edgeEventType,
ActionType.ATTRIBUTES_UPDATED,
entityId,
entityNode);
} catch (Exception e) {
log.error("[{}] Failed to send attribute updates to the edge", edge.getName(), e);
} }
} }
if (!uniqueEntityRelations.isEmpty()) { }
log.trace("[{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), uniqueEntityRelations.size());
for (EntityRelation relation : uniqueEntityRelations) { @Override
try { public void onFailure(Throwable t) {
RelationUpdateMsg relationUpdateMsg =
relationUpdateMsgConstructor.constructRelationUpdatedMsg( }
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, }, dbCallbackExecutorService);
relation);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() // TODO: voba - push shared attributes to edge?
.setRelationUpdateMsg(relationUpdateMsg) ListenableFuture<List<AttributeKvEntry>> shAttrFuture = attributesService.findAll(edge.getTenantId(), entityId, DataConstants.SHARED_SCOPE);
.build(); ListenableFuture<List<AttributeKvEntry>> clAttrFuture = attributesService.findAll(edge.getTenantId(), entityId, DataConstants.CLIENT_SCOPE);
outputStream.onNext(ResponseMsg.newBuilder() }
.setEntityUpdateMsg(entityUpdateMsg) }
.build());
} catch (Exception e) { private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) {
log.error("Exception during loading relation [{}] to edge on sync!", relation, e); switch (entityType) {
case DEVICE:
return EdgeEventType.DEVICE;
case ASSET:
return EdgeEventType.ASSET;
case ENTITY_VIEW:
return EdgeEventType.ENTITY_VIEW;
default:
return null;
}
}
@Override
public void processRelationRequestMsg(Edge edge, RelationRequestMsg relationRequestMsg) {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(
EntityType.valueOf(relationRequestMsg.getEntityType()),
new UUID(relationRequestMsg.getEntityIdMSB(), relationRequestMsg.getEntityIdLSB()));
List<ListenableFuture<List<EntityRelation>>> futures = new ArrayList<>();
futures.add(findRelationByQuery(edge, entityId, EntitySearchDirection.FROM));
futures.add(findRelationByQuery(edge, entityId, EntitySearchDirection.TO));
ListenableFuture<List<List<EntityRelation>>> relationsListFuture = Futures.allAsList(futures);
Futures.addCallback(relationsListFuture, new FutureCallback<List<List<EntityRelation>>>() {
@Override
public void onSuccess(@Nullable List<List<EntityRelation>> relationsList) {
try {
if (!relationsList.isEmpty()) {
for (List<EntityRelation> entityRelations : relationsList) {
log.trace("[{}] [{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), entityId, entityRelations.size());
for (EntityRelation relation : entityRelations) {
try {
if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
!relation.getTo().getEntityType().equals(EntityType.EDGE)) {
saveEdgeEvent(edge.getTenantId(),
edge.getId(),
EdgeEventType.RELATION,
ActionType.ADDED,
null,
mapper.valueToTree(relation));
}
} catch (Exception e) {
log.error("Exception during loading relation [{}] to edge on sync!", relation, e);
}
} }
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading relation(s) to edge on sync!", e); log.error("Exception during loading relation(s) to edge on sync!", e);
} }
return null; }
}, ctx.getDbCallbackExecutor());
} else { @Override
return Futures.immediateFuture(null); public void onFailure(Throwable t) {
} log.error("Exception during loading relation(s) to edge on sync!", t);
}
}, dbCallbackExecutorService);
} }
private ListenableFuture<List<EntityRelation>> syncRelations(Edge edge, EntityId entityId, EntitySearchDirection direction) { private ListenableFuture<List<EntityRelation>> findRelationByQuery(Edge edge, EntityId entityId, EntitySearchDirection direction) {
EntityRelationsQuery query = new EntityRelationsQuery(); EntityRelationsQuery query = new EntityRelationsQuery();
query.setParameters(new RelationsSearchParameters(entityId, direction, -1, false)); query.setParameters(new RelationsSearchParameters(entityId, direction, -1, false));
return relationService.findByQuery(edge.getTenantId(), query); return relationService.findByQuery(edge.getTenantId(), query);
} }
@Override @Override
public void syncRuleChainMetadata(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg, StreamObserver<ResponseMsg> outputStream) { public void processDeviceCredentialsRequestMsg(Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg) {
if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) { if (deviceCredentialsRequestMsg.getDeviceIdMSB() != 0 && deviceCredentialsRequestMsg.getDeviceIdLSB() != 0) {
RuleChainId ruleChainId = new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB())); DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsRequestMsg.getDeviceIdMSB(), deviceCredentialsRequestMsg.getDeviceIdLSB()));
RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(edge.getTenantId(), ruleChainId); saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.DEVICE, ActionType.CREDENTIALS_UPDATED, deviceId, null);
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = }
ruleChainUpdateMsgConstructor.constructRuleChainMetadataUpdatedMsg( }
UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE,
ruleChainMetaData); @Override
if (ruleChainMetadataUpdateMsg != null) { public void processUserCredentialsRequestMsg(Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg) {
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() if (userCredentialsRequestMsg.getUserIdMSB() != 0 && userCredentialsRequestMsg.getUserIdLSB() != 0) {
.setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg) UserId userId = new UserId(new UUID(userCredentialsRequestMsg.getUserIdMSB(), userCredentialsRequestMsg.getUserIdLSB()));
.build(); saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, ActionType.CREDENTIALS_UPDATED, userId, null);
outputStream.onNext(ResponseMsg.newBuilder() }
.setEntityUpdateMsg(entityUpdateMsg) }
.build());
} private void saveEdgeEvent(TenantId tenantId,
EdgeId edgeId,
EdgeEventType edgeEventType,
ActionType edgeEventAction,
EntityId entityId,
JsonNode entityBody) {
log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], edgeEventType [{}], edgeEventAction[{}], entityId [{}], entityBody [{}]",
tenantId, edgeId, edgeEventType, edgeEventAction, entityId, entityBody);
EdgeEvent edgeEvent = new EdgeEvent();
edgeEvent.setTenantId(tenantId);
edgeEvent.setEdgeId(edgeId);
edgeEvent.setEdgeEventType(edgeEventType);
edgeEvent.setEdgeEventAction(edgeEventAction.name());
if (entityId != null) {
edgeEvent.setEntityId(entityId.getId());
} }
edgeEvent.setEntityBody(entityBody);
edgeEventService.saveAsync(edgeEvent);
} }
} }

19
application/src/main/java/org/thingsboard/server/service/edge/rpc/init/SyncEdgeService.java

@ -15,15 +15,24 @@
*/ */
package org.thingsboard.server.service.edge.rpc.init; package org.thingsboard.server.service.edge.rpc.init;
import io.grpc.stub.StreamObserver;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.gen.edge.ResponseMsg; import org.thingsboard.server.gen.edge.AttributesRequestMsg;
import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.RelationRequestMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg; import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg;
import org.thingsboard.server.service.edge.EdgeContextComponent; import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg;
public interface SyncEdgeService { public interface SyncEdgeService {
void sync(EdgeContextComponent ctx, Edge edge, StreamObserver<ResponseMsg> outputStream); void sync(Edge edge);
void syncRuleChainMetadata(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg, StreamObserver<ResponseMsg> outputStream); void processRuleChainMetadataRequestMsg(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg);
void processAttributesRequestMsg(Edge edge, AttributesRequestMsg attributesRequestMsg);
void processRelationRequestMsg(Edge edge, RelationRequestMsg relationRequestMsg);
void processDeviceCredentialsRequestMsg(Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg);
void processUserCredentialsRequestMsg(Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg);
} }

9
application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java

@ -33,9 +33,9 @@ public class TbCoreConsumerStats {
private final AtomicInteger claimDeviceCounter = new AtomicInteger(0); private final AtomicInteger claimDeviceCounter = new AtomicInteger(0);
private final AtomicInteger deviceStateCounter = new AtomicInteger(0); private final AtomicInteger deviceStateCounter = new AtomicInteger(0);
private final AtomicInteger edgeNotificationCounter = new AtomicInteger(0);
private final AtomicInteger subscriptionMsgCounter = new AtomicInteger(0); private final AtomicInteger subscriptionMsgCounter = new AtomicInteger(0);
private final AtomicInteger toCoreNotificationsCounter = new AtomicInteger(0); private final AtomicInteger toCoreNotificationsCounter = new AtomicInteger(0);
private final AtomicInteger edgeNotificationMsgCounter = new AtomicInteger(0);
public void log(TransportProtos.TransportToDeviceActorMsg msg) { public void log(TransportProtos.TransportToDeviceActorMsg msg) {
totalCounter.incrementAndGet(); totalCounter.incrementAndGet();
@ -69,7 +69,7 @@ public class TbCoreConsumerStats {
public void log(TransportProtos.EdgeNotificationMsgProto msg) { public void log(TransportProtos.EdgeNotificationMsgProto msg) {
totalCounter.incrementAndGet(); totalCounter.incrementAndGet();
edgeNotificationCounter.incrementAndGet(); edgeNotificationMsgCounter.incrementAndGet();
} }
public void log(TransportProtos.SubscriptionMgrMsgProto msg) { public void log(TransportProtos.SubscriptionMgrMsgProto msg) {
@ -86,12 +86,13 @@ public class TbCoreConsumerStats {
int total = totalCounter.getAndSet(0); int total = totalCounter.getAndSet(0);
if (total > 0) { if (total > 0) {
log.info("Total [{}] sessionEvents [{}] getAttr [{}] subToAttr [{}] subToRpc [{}] toDevRpc [{}] subInfo [{}] claimDevice [{}]" + log.info("Total [{}] sessionEvents [{}] getAttr [{}] subToAttr [{}] subToRpc [{}] toDevRpc [{}] subInfo [{}] claimDevice [{}]" +
" deviceState [{}] subMgr [{}] coreNfs [{}]", " deviceState [{}] subMgr [{}] coreNfs [{}] edgeNfs [{}]",
total, sessionEventCounter.getAndSet(0), total, sessionEventCounter.getAndSet(0),
getAttributesCounter.getAndSet(0), subscribeToAttributesCounter.getAndSet(0), getAttributesCounter.getAndSet(0), subscribeToAttributesCounter.getAndSet(0),
subscribeToRPCCounter.getAndSet(0), toDeviceRPCCallResponseCounter.getAndSet(0), subscribeToRPCCounter.getAndSet(0), toDeviceRPCCallResponseCounter.getAndSet(0),
subscriptionInfoCounter.getAndSet(0), claimDeviceCounter.getAndSet(0) subscriptionInfoCounter.getAndSet(0), claimDeviceCounter.getAndSet(0)
, deviceStateCounter.getAndSet(0), subscriptionMsgCounter.getAndSet(0), toCoreNotificationsCounter.getAndSet(0)); , deviceStateCounter.getAndSet(0), subscriptionMsgCounter.getAndSet(0), toCoreNotificationsCounter.getAndSet(0),
edgeNotificationMsgCounter.getAndSet(0));
} }
} }

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

@ -26,8 +26,6 @@ import org.thingsboard.server.common.data.page.TimePageLink;
public interface EdgeEventService { public interface EdgeEventService {
EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType);
ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent); ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent);
TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);

61
common/data/src/main/java/org/thingsboard/server/common/data/EdgeUtils.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.common.data; package org.thingsboard.server.common.data;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import java.util.Set; import java.util.Set;
@ -24,50 +25,22 @@ public final class EdgeUtils {
private EdgeUtils() { private EdgeUtils() {
} }
public static boolean isAssignedToEdge(Set<ShortEdgeInfo> assignedEdges, EdgeId edgeId) { public static EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType) {
return assignedEdges != null && assignedEdges.contains(new ShortEdgeInfo(edgeId, null, null)); switch (entityType) {
} case DEVICE:
return EdgeEventType.DEVICE;
public static ShortEdgeInfo getAssignedEdgeInfo(Set<ShortEdgeInfo> assignedEdges, EdgeId edgeId) { case ASSET:
if (assignedEdges != null) { return EdgeEventType.ASSET;
for (ShortEdgeInfo edgeInfo : assignedEdges) { case ENTITY_VIEW:
if (edgeInfo.getEdgeId().equals(edgeId)) { return EdgeEventType.ENTITY_VIEW;
return edgeInfo; case DASHBOARD:
} return EdgeEventType.DASHBOARD;
} case USER:
} return EdgeEventType.USER;
return null; case ALARM:
} return EdgeEventType.ALARM;
default:
public static boolean addAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) { return null;
if (assignedEdges != null && assignedEdges.contains(edgeInfo)) {
return false;
} else {
if (assignedEdges != null) {
assignedEdges.add(edgeInfo);
return true;
} else {
return false;
}
}
}
public static boolean updateAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) {
if (assignedEdges != null && assignedEdges.contains(edgeInfo)) {
assignedEdges.remove(edgeInfo);
assignedEdges.add(edgeInfo);
return true;
} else {
return false;
}
}
public static boolean removeAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) {
if (assignedEdges != null && assignedEdges.contains(edgeInfo)) {
assignedEdges.remove(edgeInfo);
return true;
} else {
return false;
} }
} }
} }

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

@ -43,7 +43,8 @@ public enum ActionType {
LOGOUT(false), LOGOUT(false),
LOCKOUT(false), LOCKOUT(false),
ASSIGNED_TO_EDGE(false), // log edge name ASSIGNED_TO_EDGE(false), // log edge name
UNASSIGNED_FROM_EDGE(false); // log edge name UNASSIGNED_FROM_EDGE(false), // log edge name
CREDENTIALS_REQUEST(false); // request credentials from edge
private final boolean isRead; private final boolean isRead;

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

@ -20,7 +20,6 @@ import lombok.Data;
import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.EdgeEventId; import org.thingsboard.server.common.data.id.EdgeEventId;
import org.thingsboard.server.common.data.id.EdgeId; 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.id.TenantId;
import java.util.UUID; import java.util.UUID;

12
common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java

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

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

@ -48,15 +48,17 @@ message ResponseMsg {
message EntityUpdateMsg { message EntityUpdateMsg {
DeviceUpdateMsg deviceUpdateMsg = 1; DeviceUpdateMsg deviceUpdateMsg = 1;
RuleChainUpdateMsg ruleChainUpdateMsg = 2; DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg = 2;
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = 3; RuleChainUpdateMsg ruleChainUpdateMsg = 3;
DashboardUpdateMsg dashboardUpdateMsg = 4; RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = 4;
AssetUpdateMsg assetUpdateMsg = 5; DashboardUpdateMsg dashboardUpdateMsg = 5;
EntityViewUpdateMsg entityViewUpdateMsg = 6; AssetUpdateMsg assetUpdateMsg = 6;
AlarmUpdateMsg alarmUpdateMsg = 7; EntityViewUpdateMsg entityViewUpdateMsg = 7;
UserUpdateMsg userUpdateMsg = 8; AlarmUpdateMsg alarmUpdateMsg = 8;
CustomerUpdateMsg customerUpdateMsg = 9; UserUpdateMsg userUpdateMsg = 9;
RelationUpdateMsg relationUpdateMsg = 10; UserCredentialsUpdateMsg userCredentialsUpdateMsg = 10;
CustomerUpdateMsg customerUpdateMsg = 11;
RelationUpdateMsg relationUpdateMsg = 12;
} }
enum RequestMsgType { enum RequestMsgType {
@ -169,9 +171,14 @@ message DeviceUpdateMsg {
string name = 4; string name = 4;
string type = 5; string type = 5;
string label = 6; string label = 6;
string credentialsType = 7; }
string credentialsId = 8;
string credentialsValue = 9; message DeviceCredentialsUpdateMsg {
int64 deviceIdMSB = 1;
int64 deviceIdLSB = 2;
string credentialsType = 3;
string credentialsId = 4;
string credentialsValue = 5;
} }
message AssetUpdateMsg { message AssetUpdateMsg {
@ -248,8 +255,13 @@ message UserUpdateMsg {
string firstName = 6; string firstName = 6;
string lastName = 7; string lastName = 7;
string additionalInfo = 8; string additionalInfo = 8;
bool enabled = 9; }
string password = 10;
message UserCredentialsUpdateMsg {
int64 userIdMSB = 1;
int64 userIdLSB = 2;
bool enabled = 3;
string password = 4;
} }
message RuleChainMetadataRequestMsg { message RuleChainMetadataRequestMsg {
@ -257,6 +269,28 @@ message RuleChainMetadataRequestMsg {
int64 ruleChainIdLSB = 2; int64 ruleChainIdLSB = 2;
} }
message AttributesRequestMsg {
int64 entityIdMSB = 1;
int64 entityIdLSB = 2;
string entityType = 3;
}
message RelationRequestMsg {
int64 entityIdMSB = 1;
int64 entityIdLSB = 2;
string entityType = 3;
}
message UserCredentialsRequestMsg {
int64 userIdMSB = 1;
int64 userIdLSB = 2;
}
message DeviceCredentialsRequestMsg {
int64 deviceIdMSB = 1;
int64 deviceIdLSB = 2;
}
enum EdgeEntityType { enum EdgeEntityType {
DEVICE = 0; DEVICE = 0;
ASSET = 1; ASSET = 1;
@ -270,8 +304,13 @@ message UplinkMsg {
int32 uplinkMsgId = 1; int32 uplinkMsgId = 1;
repeated EntityDataProto entityData = 2; repeated EntityDataProto entityData = 2;
repeated DeviceUpdateMsg deviceUpdateMsg = 3; repeated DeviceUpdateMsg deviceUpdateMsg = 3;
repeated AlarmUpdateMsg alarmUpdateMsg = 4; repeated DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg = 4;
repeated RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg = 5; repeated AlarmUpdateMsg alarmUpdateMsg = 5;
repeated RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg = 6;
repeated AttributesRequestMsg attributesRequestMsg = 7;
repeated RelationRequestMsg relationRequestMsg = 8;
repeated UserCredentialsRequestMsg userCredentialsRequestMsg = 9;
repeated DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 10;
} }
message UplinkResponseMsg { message UplinkResponseMsg {
@ -282,5 +321,6 @@ message UplinkResponseMsg {
message DownlinkMsg { message DownlinkMsg {
int32 downlinkMsgId = 1; int32 downlinkMsgId = 1;
repeated EntityDataProto entityData = 2; repeated EntityDataProto entityData = 2;
repeated DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 3;
} }

2
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java

@ -232,7 +232,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
if (edge == null) { if (edge == null) {
throw new DataValidationException("Can't assign dashboard to non-existent edge!"); throw new DataValidationException("Can't assign dashboard to non-existent edge!");
} }
if (!edge.getTenantId().getId().equals(dashboard.getTenantId().getId())) { if (!edge.getTenantId().equals(dashboard.getTenantId())) {
throw new DataValidationException("Can't assign dashboard to edge from different tenant!"); throw new DataValidationException("Can't assign dashboard to edge from different tenant!");
} }
try { try {

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

@ -20,9 +20,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TimePageData; import org.thingsboard.server.common.data.page.TimePageData;
@ -39,27 +37,6 @@ public class BaseEdgeEventService implements EdgeEventService {
@Autowired @Autowired
public EdgeEventDao edgeEventDao; public EdgeEventDao edgeEventDao;
@Override
public EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType) {
switch (entityType) {
case DEVICE:
return EdgeEventType.DEVICE;
case ASSET:
return EdgeEventType.ASSET;
case ENTITY_VIEW:
return EdgeEventType.ENTITY_VIEW;
case DASHBOARD:
return EdgeEventType.DASHBOARD;
case USER:
return EdgeEventType.USER;
case ALARM:
return EdgeEventType.ALARM;
default:
log.warn("Failed to push notification to edge service. Unsupported entity type [{}]", entityType);
return null;
}
}
@Override @Override
public ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent) { public ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent) {
edgeEventValidator.validate(edgeEvent, EdgeEvent::getTenantId); edgeEventValidator.validate(edgeEvent, EdgeEvent::getTenantId);

16
dao/src/main/java/org/thingsboard/server/dao/edge/CassandraEdgeDao.java

@ -22,17 +22,13 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.model.nosql.EdgeEntity; import org.thingsboard.server.dao.model.nosql.EdgeEntity;
import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao; import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao;
import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.relation.RelationDao;
@ -113,19 +109,17 @@ public class CassandraEdgeDao extends CassandraAbstractSearchTextDao<EdgeEntity,
public ListenableFuture<List<Edge>> findEdgesByTenantIdAndRuleChainId(UUID tenantId, UUID ruleChainId) { public ListenableFuture<List<Edge>> findEdgesByTenantIdAndRuleChainId(UUID tenantId, UUID ruleChainId) {
log.debug("Try to find edges by tenantId [{}], ruleChainId [{}]", tenantId, ruleChainId); log.debug("Try to find edges by tenantId [{}], ruleChainId [{}]", tenantId, ruleChainId);
ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new RuleChainId(ruleChainId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new RuleChainId(ruleChainId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
return Futures.transformAsync(relations, input -> { return transformFromRelationToEdge(tenantId, relations);
List<ListenableFuture<Edge>> edgeFutures = new ArrayList<>(input.size());
for (EntityRelation relation : input) {
edgeFutures.add(findByIdAsync(new TenantId(tenantId), relation.getFrom().getId()));
}
return Futures.successfulAsList(edgeFutures);
}, MoreExecutors.directExecutor());
} }
@Override @Override
public ListenableFuture<List<Edge>> findEdgesByTenantIdAndDashboardId(UUID tenantId, UUID dashboardId) { public ListenableFuture<List<Edge>> findEdgesByTenantIdAndDashboardId(UUID tenantId, UUID dashboardId) {
log.debug("Try to find edges by tenantId [{}], dashboardId [{}]", tenantId, dashboardId); log.debug("Try to find edges by tenantId [{}], dashboardId [{}]", tenantId, dashboardId);
ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new DashboardId(dashboardId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new DashboardId(dashboardId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
return transformFromRelationToEdge(tenantId, relations);
}
private ListenableFuture<List<Edge>> transformFromRelationToEdge(UUID tenantId, ListenableFuture<List<EntityRelation>> relations) {
return Futures.transformAsync(relations, input -> { return Futures.transformAsync(relations, input -> {
List<ListenableFuture<Edge>> edgeFutures = new ArrayList<>(input.size()); List<ListenableFuture<Edge>> edgeFutures = new ArrayList<>(input.size());
for (EntityRelation relation : input) { for (EntityRelation relation : input) {

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

@ -414,7 +414,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
if (edge == null) { if (edge == null) {
throw new DataValidationException("Can't assign ruleChain to non-existent edge!"); throw new DataValidationException("Can't assign ruleChain to non-existent edge!");
} }
if (!edge.getTenantId().getId().equals(ruleChain.getTenantId().getId())) { if (!edge.getTenantId().equals(ruleChain.getTenantId())) {
throw new DataValidationException("Can't assign ruleChain to edge from different tenant!"); throw new DataValidationException("Can't assign ruleChain to edge from different tenant!");
} }
try { try {

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

@ -151,19 +151,17 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple
public ListenableFuture<List<Edge>> findEdgesByTenantIdAndRuleChainId(UUID tenantId, UUID ruleChainId) { public ListenableFuture<List<Edge>> findEdgesByTenantIdAndRuleChainId(UUID tenantId, UUID ruleChainId) {
log.debug("Try to find edges by tenantId [{}], ruleChainId [{}]", tenantId, ruleChainId); log.debug("Try to find edges by tenantId [{}], ruleChainId [{}]", tenantId, ruleChainId);
ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new RuleChainId(ruleChainId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new RuleChainId(ruleChainId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
return Futures.transformAsync(relations, input -> { return transformFromRelationToEdge(tenantId, relations);
List<ListenableFuture<Edge>> edgeFutures = new ArrayList<>(input.size());
for (EntityRelation relation : input) {
edgeFutures.add(findByIdAsync(new TenantId(tenantId), relation.getFrom().getId()));
}
return Futures.successfulAsList(edgeFutures);
}, MoreExecutors.directExecutor());
} }
@Override @Override
public ListenableFuture<List<Edge>> findEdgesByTenantIdAndDashboardId(UUID tenantId, UUID dashboardId) { public ListenableFuture<List<Edge>> findEdgesByTenantIdAndDashboardId(UUID tenantId, UUID dashboardId) {
log.debug("Try to find edges by tenantId [{}], dashboardId [{}]", tenantId, dashboardId); log.debug("Try to find edges by tenantId [{}], dashboardId [{}]", tenantId, dashboardId);
ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new DashboardId(dashboardId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new DashboardId(dashboardId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
return transformFromRelationToEdge(tenantId, relations);
}
private ListenableFuture<List<Edge>> transformFromRelationToEdge(UUID tenantId, ListenableFuture<List<EntityRelation>> relations) {
return Futures.transformAsync(relations, input -> { return Futures.transformAsync(relations, input -> {
List<ListenableFuture<Edge>> edgeFutures = new ArrayList<>(input.size()); List<ListenableFuture<Edge>> edgeFutures = new ArrayList<>(input.size());
for (EntityRelation relation : input) { for (EntityRelation relation : input) {

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

@ -332,6 +332,21 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest {
Assert.assertEquals(1, result.size()); Assert.assertEquals(1, result.size());
} }
@Test
public void setDefaultRootEdgeRuleChain() throws Exception {
RuleChainId ruleChainId1 = saveRuleChainAndSetDefaultEdge("Default Edge Rule Chain 1");
RuleChainId ruleChainId2 = saveRuleChainAndSetDefaultEdge("Default Edge Rule Chain 2");
ruleChainService.setDefaultRootEdgeRuleChain(tenantId, ruleChainId1);
ruleChainService.setDefaultRootEdgeRuleChain(tenantId, ruleChainId2);
RuleChain ruleChainById = ruleChainService.findRuleChainById(tenantId, ruleChainId1);
Assert.assertFalse(ruleChainById.isRoot());
ruleChainById = ruleChainService.findRuleChainById(tenantId, ruleChainId2);
Assert.assertTrue(ruleChainById.isRoot());
}
private RuleChainId saveRuleChainAndSetDefaultEdge(String name) { private RuleChainId saveRuleChainAndSetDefaultEdge(String name) {
RuleChain edgeRuleChain = new RuleChain(); RuleChain edgeRuleChain = new RuleChain();
edgeRuleChain.setTenantId(tenantId); edgeRuleChain.setTenantId(tenantId);

189
rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java

@ -45,7 +45,8 @@ import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.data.UpdateMessage;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmSeverity;
@ -56,10 +57,12 @@ import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.audit.AuditLog; import org.thingsboard.server.common.data.audit.AuditLog;
import org.thingsboard.server.common.data.device.DeviceSearchQuery; import org.thingsboard.server.common.data.device.DeviceSearchQuery;
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
@ -1978,6 +1981,190 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
} }
} }
public Edge saveEdge(Edge edge) {
return restTemplate.postForEntity(baseURL + "/api/edge", edge, Edge.class).getBody();
}
public void deleteEdge(EdgeId edgeId) {
restTemplate.delete(baseURL + "/api/edge/{edgeId}", edgeId.getId());
}
public Optional<Edge> getEdgeById(EdgeId edgeId) {
try {
ResponseEntity<Edge> edge = restTemplate.getForEntity(baseURL + "/api/edge/{edgeId}", Edge.class, edgeId.getId());
return Optional.ofNullable(edge.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public Optional<Edge> assignEdgeToCustomer(CustomerId customerId, EdgeId edgeId) {
try {
ResponseEntity<Edge> edge = restTemplate.postForEntity(baseURL + "/api/customer/{customerId}/edge/{edgeId}", null, Edge.class, customerId.getId(), edgeId.getId());
return Optional.ofNullable(edge.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public Optional<Edge> unassignEdgeFromCustomer(EdgeId edgeId) {
try {
ResponseEntity<Edge> edge = restTemplate.exchange(baseURL + "/api/customer/edge/{edgeId}", HttpMethod.DELETE, HttpEntity.EMPTY, Edge.class, edgeId.getId());
return Optional.ofNullable(edge.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public Optional<Device> assignDeviceToEdge(EdgeId edgeId, DeviceId deviceId) {
try {
ResponseEntity<Device> device = restTemplate.postForEntity(baseURL + "/api/edge/{edgeId}/device/{deviceId}", null, Device.class, edgeId.getId(), deviceId.getId());
return Optional.ofNullable(device.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public Optional<Device> unassignDeviceFromEdge(DeviceId deviceId) {
try {
ResponseEntity<Device> device = restTemplate.exchange(baseURL + "/api/edge/device/{deviceId}", HttpMethod.DELETE, HttpEntity.EMPTY, Device.class, deviceId.getId());
return Optional.ofNullable(device.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public TextPageData<Device> getEdgeDevices(EdgeId edgeId, String deviceType, TextPageLink pageLink) {
Map<String, String> params = new HashMap<>();
params.put("edgeId", edgeId.getId().toString());
params.put("type", deviceType);
addPageLinkToParam(params, pageLink);
return restTemplate.exchange(
baseURL + "/api/edge/{edgeId}/devices?type={type}&" + getUrlParams(pageLink),
HttpMethod.GET, HttpEntity.EMPTY,
new ParameterizedTypeReference<TextPageData<Device>>() {
}, params).getBody();
}
public Optional<Asset> assignAssetToEdge(EdgeId edgeId, AssetId assetId) {
try {
ResponseEntity<Asset> asset = restTemplate.postForEntity(baseURL + "/api/edge/{edgeId}/asset/{assetId}", null, Asset.class, edgeId.getId(), assetId.getId());
return Optional.ofNullable(asset.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public Optional<Asset> unassignAssetFromEdge(AssetId assetId) {
try {
ResponseEntity<Asset> asset = restTemplate.exchange(baseURL + "/api/edge/asset/{assetId}", HttpMethod.DELETE, HttpEntity.EMPTY, Asset.class, assetId.getId());
return Optional.ofNullable(asset.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public TextPageData<Asset> getEdgeAssets(EdgeId edgeId, String assetType, TextPageLink pageLink) {
Map<String, String> params = new HashMap<>();
params.put("edgeId", edgeId.getId().toString());
params.put("type", assetType);
addPageLinkToParam(params, pageLink);
return restTemplate.exchange(
baseURL + "/api/edge/{edgeId}/assets?type={type}&" + getUrlParams(pageLink),
HttpMethod.GET, HttpEntity.EMPTY,
new ParameterizedTypeReference<TextPageData<Asset>>() {
}, params).getBody();
}
public TextPageData<Edge> getTenantEdges(String type, TextPageLink pageLink) {
Map<String, String> params = new HashMap<>();
params.put("type", type);
addPageLinkToParam(params, pageLink);
return restTemplate.exchange(
baseURL + "/api/tenant/edges?type={type}&" + getUrlParams(pageLink),
HttpMethod.GET, HttpEntity.EMPTY,
new ParameterizedTypeReference<TextPageData<Edge>>() {
}, params).getBody();
}
public Optional<Edge> getTenantEdge(String edgeName) {
try {
ResponseEntity<Edge> edge = restTemplate.getForEntity(baseURL + "/api/tenant/edges?edgeName={edgeName}", Edge.class, edgeName);
return Optional.ofNullable(edge.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public TextPageData<Edge> getCustomerEdges(CustomerId customerId, String edgeType, TextPageLink pageLink) {
Map<String, String> params = new HashMap<>();
params.put("customerId", customerId.getId().toString());
params.put("type", edgeType);
addPageLinkToParam(params, pageLink);
return restTemplate.exchange(
baseURL + "/api/customer/{customerId}/edges?type={type}&" + getUrlParams(pageLink),
HttpMethod.GET, HttpEntity.EMPTY,
new ParameterizedTypeReference<TextPageData<Edge>>() {
}, params).getBody();
}
public List<Edge> getEdgesByIds(List<EdgeId> edgeIds) {
return restTemplate.exchange(baseURL + "/api/edges?edgeIds={edgeIds}",
HttpMethod.GET,
HttpEntity.EMPTY, new ParameterizedTypeReference<List<Edge>>() {
}, listIdsToString(edgeIds)).getBody();
}
public List<Edge> findByQuery(EdgeSearchQuery query) {
return restTemplate.exchange(
baseURL + "/api/edges",
HttpMethod.POST,
new HttpEntity<>(query),
new ParameterizedTypeReference<List<Edge>>() {
}).getBody();
}
public List<EntitySubtype> getEdgeTypes() {
return restTemplate.exchange(
baseURL + "/api/edge/types",
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<List<EntitySubtype>>() {
}).getBody();
}
@Deprecated @Deprecated
public Optional<JsonNode> getAttributes(String accessToken, String clientKeys, String sharedKeys) { public Optional<JsonNode> getAttributes(String accessToken, String clientKeys, String sharedKeys) {
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();

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

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

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

@ -37,9 +37,7 @@ import org.thingsboard.server.common.msg.TbMsg;
"Will create new Customer if it doesn't exists and 'Create new Customer if not exists' is set to true.", "Will create new Customer if it doesn't exists and 'Create new Customer if not exists' is set to true.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeAssignToCustomerConfig", configDirective = "tbActionNodeAssignToCustomerConfig",
icon = "add_circle", icon = "add_circle")
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbAssignToCustomerNode extends TbAbstractCustomerActionNode<TbAssignToCustomerNodeConfiguration> { public class TbAssignToCustomerNode extends TbAbstractCustomerActionNode<TbAssignToCustomerNodeConfiguration> {
@Override @Override

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

@ -45,9 +45,7 @@ import org.thingsboard.server.common.msg.TbMsg;
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.", "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeClearAlarmConfig", configDirective = "tbActionNodeClearAlarmConfig",
icon = "notifications_off", icon = "notifications_off")
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfiguration> { public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfiguration> {
@Override @Override

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

@ -57,9 +57,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
"Changes message originator to related entity view and produces new messages according to count of updated entity views", "Changes message originator to related entity view and produces new messages according to count of updated entity views",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig", configDirective = "tbNodeEmptyConfig",
icon = "content_copy", icon = "content_copy")
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbCopyAttributesToEntityViewNode implements TbNode { public class TbCopyAttributesToEntityViewNode implements TbNode {
EmptyNodeConfiguration config; EmptyNodeConfiguration config;

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

@ -51,9 +51,7 @@ import java.util.List;
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.", "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeCreateAlarmConfig", configDirective = "tbActionNodeCreateAlarmConfig",
icon = "notifications_active", icon = "notifications_active")
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConfiguration> { public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConfiguration> {
private static ObjectMapper mapper = new ObjectMapper(); private static ObjectMapper mapper = new ObjectMapper();

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

@ -54,9 +54,7 @@ import java.util.List;
nodeDetails = "If the relation already exists or successfully created - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.", nodeDetails = "If the relation already exists or successfully created - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeCreateRelationConfig", configDirective = "tbActionNodeCreateRelationConfig",
icon = "add_circle", icon = "add_circle")
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateRelationNodeConfiguration> { public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateRelationNodeConfiguration> {
@Override @Override

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

@ -44,9 +44,7 @@ import java.util.List;
nodeDetails = "If the relation(s) successfully deleted - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.", nodeDetails = "If the relation(s) successfully deleted - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeDeleteRelationConfig", configDirective = "tbActionNodeDeleteRelationConfig",
icon = "remove_circle", icon = "remove_circle")
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> { public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> {
@Override @Override

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

@ -37,10 +37,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.", "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeLogConfig", configDirective = "tbActionNodeLogConfig",
icon = "menu", icon = "menu")
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbLogNode implements TbNode { public class TbLogNode implements TbNode {
private TbLogNodeConfiguration config; private TbLogNodeConfiguration config;

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

@ -44,9 +44,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
nodeDetails = "Count incoming messages for specified interval and produces POST_TELEMETRY_REQUEST msg with messages count", nodeDetails = "Count incoming messages for specified interval and produces POST_TELEMETRY_REQUEST msg with messages count",
icon = "functions", icon = "functions",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeMsgCountConfig", configDirective = "tbActionNodeMsgCountConfig")
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
)
public class TbMsgCountNode implements TbNode { public class TbMsgCountNode implements TbNode {
private static final String TB_MSG_COUNT_NODE_MSG = "TbMsgCountNodeMsg"; private static final String TB_MSG_COUNT_NODE_MSG = "TbMsgCountNodeMsg";

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java

@ -78,7 +78,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
" otherwise, the message will be routed via <b>success</b> chain.", " otherwise, the message will be routed via <b>success</b> chain.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeCustomTableConfig", configDirective = "tbActionNodeCustomTableConfig",
icon = "file_upload" icon = "file_upload",
ruleChainTypes = RuleChainType.CORE
) )
public class TbSaveToCustomCassandraTableNode implements TbNode { public class TbSaveToCustomCassandraTableNode implements TbNode {

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

@ -21,9 +21,13 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.*; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@RuleNode( @RuleNode(
@ -34,8 +38,7 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDetails = "Finds target Entity Customer by Customer name pattern and then unassign Originator Entity from this customer.", nodeDetails = "Finds target Entity Customer by Customer name pattern and then unassign Originator Entity from this customer.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeUnAssignToCustomerConfig", configDirective = "tbActionNodeUnAssignToCustomerConfig",
icon = "remove_circle", icon = "remove_circle"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbUnassignFromCustomerNode extends TbAbstractCustomerActionNode<TbUnassignFromCustomerNodeConfiguration> { public class TbUnassignFromCustomerNode extends TbAbstractCustomerActionNode<TbUnassignFromCustomerNodeConfiguration> {

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

@ -46,8 +46,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.", "For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeSnsConfig", configDirective = "tbActionNodeSnsConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+", iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbSnsNode implements TbNode { public class TbSnsNode implements TbNode {

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

@ -51,8 +51,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
" For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.", " For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeSqsConfig", configDirective = "tbActionNodeSqsConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+", iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbSqsNode implements TbNode { public class TbSqsNode implements TbNode {

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

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

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

@ -46,8 +46,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
nodeDetails = "Delays messages for configurable period. Please note, this node acknowledges the message from the current queue (message will be removed from queue)", nodeDetails = "Delays messages for configurable period. Please note, this node acknowledges the message from the current queue (message will be removed from queue)",
icon = "pause", icon = "pause",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeMsgDelayConfig", configDirective = "tbActionNodeMsgDelayConfig"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbMsgDelayNode implements TbNode { public class TbMsgDelayNode implements TbNode {

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

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.rule.engine.edge; package org.thingsboard.rule.engine.edge;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
@ -28,6 +29,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
@ -38,6 +40,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.msg.session.SessionMsgType;
@ -55,7 +58,8 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
nodeDetails = "Pushes messages to edge, if Message Originator assigned to particular edge or is EDGE entity. This node is used only on Cloud instances to push messages from Cloud to Edge. Supports only DEVICE, ENTITY_VIEW, ASSET and EDGE Message Originator(s).", nodeDetails = "Pushes messages to edge, if Message Originator assigned to particular edge or is EDGE entity. This node is used only on Cloud instances to push messages from Cloud to Edge. Supports only DEVICE, ENTITY_VIEW, ASSET and EDGE Message Originator(s).",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbNodeEmptyConfig", configDirective = "tbNodeEmptyConfig",
icon = "cloud_download" icon = "cloud_download",
ruleChainTypes = RuleChainType.CORE
) )
public class TbMsgPushToEdgeNode implements TbNode { public class TbMsgPushToEdgeNode implements TbNode {
@ -77,33 +81,38 @@ public class TbMsgPushToEdgeNode implements TbNode {
if (isSupportedOriginator(msg.getOriginator().getEntityType())) { if (isSupportedOriginator(msg.getOriginator().getEntityType())) {
if (isSupportedMsgType(msg.getType())) { if (isSupportedMsgType(msg.getType())) {
ListenableFuture<EdgeId> getEdgeIdFuture = getEdgeIdByOriginatorId(ctx, ctx.getTenantId(), msg.getOriginator()); ListenableFuture<EdgeId> getEdgeIdFuture = getEdgeIdByOriginatorId(ctx, ctx.getTenantId(), msg.getOriginator());
Futures.transform(getEdgeIdFuture, edgeId -> { Futures.addCallback(getEdgeIdFuture, new FutureCallback<EdgeId>() {
EdgeEventType edgeEventTypeByEntityType = ctx.getEdgeEventService().getEdgeEventTypeByEntityType(msg.getOriginator().getEntityType()); @Override
if (edgeEventTypeByEntityType == null) { public void onSuccess(@Nullable EdgeId edgeId) {
log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType()); EdgeEventType edgeEventTypeByEntityType = EdgeUtils.getEdgeEventTypeByEntityType(msg.getOriginator().getEntityType());
ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '" + msg.getOriginator().getEntityType() + "'")); if (edgeEventTypeByEntityType == null) {
} log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType());
EdgeEvent edgeEvent = new EdgeEvent(); ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '" + msg.getOriginator().getEntityType() + "'"));
edgeEvent.setTenantId(ctx.getTenantId());
edgeEvent.setEdgeId(edgeId);
edgeEvent.setEdgeEventAction(getActionTypeByMsgType(msg.getType()).name());
edgeEvent.setEntityId(msg.getOriginator().getId());
edgeEvent.setEdgeEventType(edgeEventTypeByEntityType);
edgeEvent.setEntityBody(json.valueToTree(msg.getData()));
ListenableFuture<EdgeEvent> saveFuture = ctx.getEdgeEventService().saveAsync(edgeEvent);
Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() {
@Override
public void onSuccess(@Nullable EdgeEvent event) {
ctx.tellNext(msg, SUCCESS);
} }
EdgeEvent edgeEvent = null;
@Override try {
public void onFailure(Throwable th) { edgeEvent = buildEdgeEvent(ctx, msg, edgeId, edgeEventTypeByEntityType);
log.error("Could not save edge event", th); } catch (JsonProcessingException e) {
ctx.tellFailure(msg, th); log.error("Failed to build edge event", e);
} }
}, ctx.getDbCallbackExecutor()); ListenableFuture<EdgeEvent> saveFuture = ctx.getEdgeEventService().saveAsync(edgeEvent);
return null; Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() {
@Override
public void onSuccess(@Nullable EdgeEvent event) {
ctx.tellNext(msg, SUCCESS);
}
@Override
public void onFailure(Throwable th) {
log.error("Could not save edge event", th);
ctx.tellFailure(msg, th);
}
}, ctx.getDbCallbackExecutor());
}
@Override
public void onFailure(Throwable t) {
ctx.tellFailure(msg, t);
}
}, ctx.getDbCallbackExecutor()); }, ctx.getDbCallbackExecutor());
} else { } else {
log.debug("Unsupported msg type {}", msg.getType()); log.debug("Unsupported msg type {}", msg.getType());
@ -115,6 +124,17 @@ public class TbMsgPushToEdgeNode implements TbNode {
} }
} }
private EdgeEvent buildEdgeEvent(TbContext ctx, TbMsg msg, EdgeId edgeId, EdgeEventType edgeEventTypeByEntityType) throws JsonProcessingException {
EdgeEvent edgeEvent = new EdgeEvent();
edgeEvent.setTenantId(ctx.getTenantId());
edgeEvent.setEdgeId(edgeId);
edgeEvent.setEdgeEventAction(getActionTypeByMsgType(msg.getType()).name());
edgeEvent.setEntityId(msg.getOriginator().getId());
edgeEvent.setEdgeEventType(edgeEventTypeByEntityType);
edgeEvent.setEntityBody(json.readTree(msg.getData()));
return edgeEvent;
}
private ActionType getActionTypeByMsgType(String msgType) { private ActionType getActionTypeByMsgType(String msgType) {
ActionType actionType; ActionType actionType;
if (SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msgType)) { if (SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msgType)) {

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

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

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

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

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

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

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

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

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

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

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

@ -35,8 +35,7 @@ import org.thingsboard.server.common.msg.session.SessionMsgType;
nodeDescription = "Route incoming messages by Message Type", nodeDescription = "Route incoming messages by Message Type",
nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.", nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig", configDirective = "tbNodeEmptyConfig"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbMsgTypeSwitchNode implements TbNode { public class TbMsgTypeSwitchNode implements TbNode {

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

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

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

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

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

@ -50,8 +50,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"<b>messageId</b> field can be accessed with <code>metadata.messageId</code>.", "<b>messageId</b> field can be accessed with <code>metadata.messageId</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodePubSubConfig", configDirective = "tbActionNodePubSubConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo=", iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo="
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbPubSubNode implements TbNode { public class TbPubSubNode implements TbNode {

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

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

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

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

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

@ -52,8 +52,7 @@ import java.util.Properties;
" from the Kafka in the Message Metadata. For example <b>partition</b> field can be accessed with <code>metadata.partition</code>.", " from the Kafka in the Message Metadata. For example <b>partition</b> field can be accessed with <code>metadata.partition</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeKafkaConfig", configDirective = "tbActionNodeKafkaConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg==", iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg=="
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbKafkaNode implements TbNode { public class TbKafkaNode implements TbNode {

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

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

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

@ -47,8 +47,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"with <code>to Email</code> Node using <code>Successful</code> chain.", "with <code>to Email</code> Node using <code>Successful</code> chain.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeSendEmailConfig", configDirective = "tbActionNodeSendEmailConfig",
icon = "send", icon = "send"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbSendEmailNode implements TbNode { public class TbSendEmailNode implements TbNode {

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

@ -41,8 +41,7 @@ import org.thingsboard.server.common.msg.TbMsg;
"To access those attributes in other nodes this template can be used " + "To access those attributes in other nodes this template can be used " +
"<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ", "<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeOriginatorAttributesConfig", configDirective = "tbEnrichmentNodeOriginatorAttributesConfig"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttributesNodeConfiguration, EntityId> { public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttributesNodeConfiguration, EntityId> {

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

@ -34,8 +34,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
"To access those attributes in other nodes this template can be used " + "To access those attributes in other nodes this template can be used " +
"<code>metadata.temperature</code>.", "<code>metadata.temperature</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbEnrichmentNodeCustomerAttributesConfig", configDirective = "tbEnrichmentNodeCustomerAttributesConfig"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode<CustomerId> { public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode<CustomerId> {

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

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

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

@ -39,8 +39,7 @@ import org.thingsboard.server.common.msg.TbMsg;
"To access those attributes in other nodes this template can be used " + "To access those attributes in other nodes this template can be used " +
"<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ", "<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeDeviceAttributesConfig", configDirective = "tbEnrichmentNodeDeviceAttributesConfig"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode<TbGetDeviceAttrNodeConfiguration, DeviceId> { public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode<TbGetDeviceAttrNodeConfiguration, DeviceId> {

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

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

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

@ -36,8 +36,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
"To access those attributes in other nodes this template can be used " + "To access those attributes in other nodes this template can be used " +
"<code>metadata.temperature</code>.", "<code>metadata.temperature</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbEnrichmentNodeRelatedAttributesConfig", configDirective = "tbEnrichmentNodeRelatedAttributesConfig"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> { public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> {

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

@ -67,8 +67,7 @@ import static org.thingsboard.server.common.data.kv.Aggregation.NONE;
"Also, the rule node allows you to select telemetry sampling order: <b>ASC</b> or <b>DESC</b>. </br>" + "Also, the rule node allows you to select telemetry sampling order: <b>ASC</b> or <b>DESC</b>. </br>" +
"<b>Note</b>: The maximum size of the fetched array is 1000 records.\n ", "<b>Note</b>: The maximum size of the fetched array is 1000 records.\n ",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase", configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbGetTelemetryNode implements TbNode { public class TbGetTelemetryNode implements TbNode {

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

@ -36,8 +36,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
"To access those attributes in other nodes this template can be used " + "To access those attributes in other nodes this template can be used " +
"<code>metadata.temperature</code>.", "<code>metadata.temperature</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbEnrichmentNodeTenantAttributesConfig", configDirective = "tbEnrichmentNodeTenantAttributesConfig"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbGetTenantAttributeNode extends TbEntityGetAttrNode<TenantId> { public class TbGetTenantAttributeNode extends TbEntityGetAttrNode<TenantId> {

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

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

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

@ -50,8 +50,7 @@ import java.util.concurrent.TimeoutException;
nodeDetails = "Will publish message payload to the MQTT broker with QoS <b>AT_LEAST_ONCE</b>.", nodeDetails = "Will publish message payload to the MQTT broker with QoS <b>AT_LEAST_ONCE</b>.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeMqttConfig", configDirective = "tbActionNodeMqttConfig",
icon = "call_split", icon = "call_split"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbMqttNode implements TbNode { public class TbMqttNode implements TbNode {

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

@ -40,8 +40,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
nodeDetails = "Will publish message payload to RabbitMQ queue.", nodeDetails = "Will publish message payload to RabbitMQ queue.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRabbitMqConfig", configDirective = "tbActionNodeRabbitMqConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4=", iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4="
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbRabbitMqNode implements TbNode { public class TbRabbitMqNode implements TbNode {

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

@ -42,8 +42,7 @@ import org.thingsboard.server.common.msg.TbMsg;
"and if your proxy with auth, the next ones should be added: \"tb.proxy.user\" and \"tb.proxy.password\" to the thingsboard.conf file.", "and if your proxy with auth, the next ones should be added: \"tb.proxy.user\" and \"tb.proxy.password\" to the thingsboard.conf file.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRestApiCallConfig", configDirective = "tbActionNodeRestApiCallConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+", iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbRestApiCallNode implements TbNode { public class TbRestApiCallNode implements TbNode {

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

@ -40,8 +40,7 @@ import java.util.UUID;
nodeDetails = "Expects messages with any message type. Will forward message body to the device.", nodeDetails = "Expects messages with any message type. Will forward message body to the device.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRpcReplyConfig", configDirective = "tbActionNodeRpcReplyConfig",
icon = "call_merge", icon = "call_merge"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbSendRPCReplyNode implements TbNode { public class TbSendRPCReplyNode implements TbNode {

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

@ -51,8 +51,7 @@ import java.util.concurrent.TimeUnit;
"If the RPC call request is originated by REST API call from user, will forward the response to user immediately.", "If the RPC call request is originated by REST API call from user, will forward the response to user immediately.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRpcRequestConfig", configDirective = "tbActionNodeRpcRequestConfig",
icon = "call_made", icon = "call_made"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbSendRPCRequestNode implements TbNode { public class TbSendRPCRequestNode implements TbNode {

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

@ -45,8 +45,7 @@ import java.util.Set;
nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type", nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeAttributesConfig", configDirective = "tbActionNodeAttributesConfig",
icon = "file_upload", icon = "file_upload"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbMsgAttributesNode implements TbNode { public class TbMsgAttributesNode implements TbNode {

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

@ -46,8 +46,7 @@ import java.util.Map;
nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type", nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeTimeseriesConfig", configDirective = "tbActionNodeTimeseriesConfig",
icon = "file_upload", icon = "file_upload"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbMsgTimeseriesNode implements TbNode { public class TbMsgTimeseriesNode implements TbNode {

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

@ -39,8 +39,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
"Subsequent messages will not be processed until the previous message processing is completed or timeout event occurs.\n" + "Subsequent messages will not be processed until the previous message processing is completed or timeout event occurs.\n" +
"Size of the queue per originator and timeout values are configurable on a system level", "Size of the queue per originator and timeout values are configurable on a system level",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig", configDirective = "tbNodeEmptyConfig"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
@Deprecated @Deprecated
public class TbSynchronizationBeginNode implements TbNode { public class TbSynchronizationBeginNode implements TbNode {

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

@ -39,8 +39,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
nodeDescription = "This Node is now deprecated. Use \"Checkpoint\" instead.", nodeDescription = "This Node is now deprecated. Use \"Checkpoint\" instead.",
nodeDetails = "", nodeDetails = "",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = ("tbNodeEmptyConfig"), configDirective = ("tbNodeEmptyConfig")
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
@Deprecated @Deprecated
public class TbSynchronizationEndNode implements TbNode { public class TbSynchronizationEndNode implements TbNode {

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

@ -47,8 +47,7 @@ import java.util.HashSet;
"Alarm Originator found only in case original Originator is <code>Alarm</code> entity.", "Alarm Originator found only in case original Originator is <code>Alarm</code> entity.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbTransformationNodeChangeOriginatorConfig", configDirective = "tbTransformationNodeChangeOriginatorConfig",
icon = "find_replace", icon = "find_replace"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbChangeOriginatorNode extends TbAbstractTransformNode { public class TbChangeOriginatorNode extends TbAbstractTransformNode {

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java

@ -38,8 +38,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
"<code>{ msg: <i style=\"color: #666;\">new payload</i>,<br/>&nbsp&nbsp&nbspmetadata: <i style=\"color: #666;\">new metadata</i>,<br/>&nbsp&nbsp&nbspmsgType: <i style=\"color: #666;\">new msgType</i> }</code><br/>" + "<code>{ msg: <i style=\"color: #666;\">new payload</i>,<br/>&nbsp&nbsp&nbspmetadata: <i style=\"color: #666;\">new metadata</i>,<br/>&nbsp&nbsp&nbspmsgType: <i style=\"color: #666;\">new msgType</i> }</code><br/>" +
"All fields in resulting object are optional and will be taken from original message if not specified.", "All fields in resulting object are optional and will be taken from original message if not specified.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbTransformationNodeScriptConfig", configDirective = "tbTransformationNodeScriptConfig"
ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
) )
public class TbTransformMsgNode extends TbAbstractTransformNode { public class TbTransformMsgNode extends TbAbstractTransformNode {

6
ui/src/app/rulechain/rulechain.controller.js

@ -1180,7 +1180,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
var saveRuleChainPromise; var saveRuleChainPromise;
if (vm.isImport) { if (vm.isImport) {
if (angular.isUndefined(vm.ruleChain.type)) { if (angular.isUndefined(vm.ruleChain.type)) {
vm.ruleChain.type = types.systemRuleChainType; vm.ruleChain.type = types.coreRuleChainType;
} }
saveRuleChainPromise = ruleChainService.saveRuleChain(vm.ruleChain); saveRuleChainPromise = ruleChainService.saveRuleChain(vm.ruleChain);
} else { } else {
@ -1269,7 +1269,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
vm.isDirty = false; vm.isDirty = false;
vm.isImport = false; vm.isImport = false;
$mdUtil.nextTick(() => { $mdUtil.nextTick(() => {
if (vm.ruleChain.type === vm.types.systemRuleChainType) { if (vm.ruleChain.type === vm.types.coreRuleChainType) {
$state.go('home.ruleChains.core.ruleChain', {ruleChainId: vm.ruleChain.id.id}); $state.go('home.ruleChains.core.ruleChain', {ruleChainId: vm.ruleChain.id.id});
} else { } else {
$state.go('home.ruleChains.edge.ruleChain', {ruleChainId: vm.ruleChain.id.id}); $state.go('home.ruleChains.edge.ruleChain', {ruleChainId: vm.ruleChain.id.id});
@ -1293,7 +1293,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
ruleNode.configuration = angular.copy(ruleNode.component.configurationDescriptor.nodeDefinition.defaultConfiguration); ruleNode.configuration = angular.copy(ruleNode.component.configurationDescriptor.nodeDefinition.defaultConfiguration);
var ruleChainId = vm.ruleChain.id ? vm.ruleChain.id.id : null; var ruleChainId = vm.ruleChain.id ? vm.ruleChain.id.id : null;
var ruleChainType = vm.ruleChain.type ? vm.ruleChain.type : types.systemRuleChainType; var ruleChainType = vm.ruleChain.type ? vm.ruleChain.type : types.coreRuleChainType;
vm.enableHotKeys = false; vm.enableHotKeys = false;

2
ui/src/app/rulechain/rulechain.routes.js

@ -82,7 +82,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
ruleNodeComponents: ruleNodeComponents:
/*@ngInject*/ /*@ngInject*/
function($stateParams, ruleChainService) { function($stateParams, ruleChainService) {
return ruleChainService.getRuleNodeComponents(types.systemRuleChainType); return ruleChainService.getRuleNodeComponents(types.coreRuleChainType);
} }
}, },
data: { data: {

8
ui/src/app/rulechain/rulechains.controller.js

@ -114,7 +114,7 @@ export default function RuleChainsController(ruleChainService, userService, edge
if (vm.ruleChainsScope === 'tenant') { if (vm.ruleChainsScope === 'tenant') {
fetchRuleChainsFunction = function (pageLink) { fetchRuleChainsFunction = function (pageLink) {
return fetchRuleChains(pageLink, types.systemRuleChainType); return fetchRuleChains(pageLink, types.coreRuleChainType);
}; };
deleteRuleChainFunction = function (ruleChainId) { deleteRuleChainFunction = function (ruleChainId) {
return deleteRuleChain(ruleChainId); return deleteRuleChain(ruleChainId);
@ -162,9 +162,9 @@ export default function RuleChainsController(ruleChainService, userService, edge
}); });
vm.ruleChainGridConfig.addItemActions.push({ vm.ruleChainGridConfig.addItemActions.push({
onAction: function ($event) { onAction: function ($event) {
importExport.importRuleChain($event, types.systemRuleChainType).then( importExport.importRuleChain($event, types.coreRuleChainType).then(
function(ruleChainImport) { function(ruleChainImport) {
$state.go('home.ruleChains.importRuleChain', {ruleChainImport:ruleChainImport, ruleChainType: types.systemRuleChainType}); $state.go('home.ruleChains.importRuleChain', {ruleChainImport:ruleChainImport, ruleChainType: types.coreRuleChainType});
} }
); );
}, },
@ -385,7 +385,7 @@ export default function RuleChainsController(ruleChainService, userService, edge
if (vm.ruleChainsScope === 'edges') { if (vm.ruleChainsScope === 'edges') {
ruleChain.type = types.edgeRuleChainType; ruleChain.type = types.edgeRuleChainType;
} else { } else {
ruleChain.type = types.systemRuleChainType; ruleChain.type = types.coreRuleChainType;
} }
} }
return ruleChainService.saveRuleChain(ruleChain); return ruleChainService.saveRuleChain(ruleChain);

Loading…
Cancel
Save