Browse Source

Don't use Rule Engine message as notification rule trigger

pull/8701/head
ViacheslavKlimov 3 years ago
parent
commit
64571eeff2
  1. 5
      application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java
  2. 2
      application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java
  3. 67
      application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java
  4. 39
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java
  5. 70
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java
  6. 38
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceActivityTriggerProcessor.java
  7. 25
      application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java
  8. 6
      application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java
  9. 22
      common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmAssignmentTrigger.java
  10. 48
      common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmCommentTrigger.java
  11. 5
      common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/ApiUsageLimitTrigger.java
  12. 49
      common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/DeviceActivityTrigger.java

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

@ -49,7 +49,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; import org.thingsboard.server.common.msg.aware.DeviceAwareMsg;
import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg; import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg;
import org.thingsboard.server.common.msg.edge.EdgeSessionMsg; import org.thingsboard.server.common.msg.edge.EdgeSessionMsg;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
@ -211,10 +210,6 @@ public class TenantActor extends RuleChainManagerActor {
log.trace("[{}] Ack message because Rule Engine is disabled", tenantId); log.trace("[{}] Ack message because Rule Engine is disabled", tenantId);
tbMsg.getCallback().onSuccess(); tbMsg.getCallback().onSuccess();
} }
systemContext.getNotificationRuleProcessor().process(RuleEngineMsgTrigger.builder()
.tenantId(tenantId)
.msg(tbMsg)
.build());
} }
private void onRuleChainMsg(RuleChainAwareMsg msg) { private void onRuleChainMsg(RuleChainAwareMsg msg) {

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

@ -77,7 +77,7 @@ public class AlarmCommentController extends BaseController {
@PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = "A JSON value representing the comment.") @RequestBody AlarmComment alarmComment) throws ThingsboardException { @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = "A JSON value representing the comment.") @RequestBody AlarmComment alarmComment) throws ThingsboardException {
checkParameter(ALARM_ID, strAlarmId); checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); Alarm alarm = checkAlarmInfoId(alarmId, Operation.WRITE);
alarmComment.setAlarmId(alarmId); alarmComment.setAlarmId(alarmId);
return tbAlarmCommentService.saveAlarmComment(alarm, alarmComment, getCurrentUser()); return tbAlarmCommentService.saveAlarmComment(alarm, alarmComment, getCurrentUser());
} }

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

@ -28,7 +28,9 @@ import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
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.AlarmComment; import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
@ -40,10 +42,12 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.msg.notification.trigger.AlarmAssignmentTrigger;
import org.thingsboard.server.common.msg.notification.trigger.AlarmCommentTrigger;
import org.thingsboard.server.common.msg.notification.trigger.EntitiesLimitTrigger; import org.thingsboard.server.common.msg.notification.trigger.EntitiesLimitTrigger;
import org.thingsboard.server.common.msg.notification.trigger.EntityActionTrigger; import org.thingsboard.server.common.msg.notification.trigger.EntityActionTrigger;
import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.dao.audit.AuditLogService;
import org.thingsboard.server.queue.notification.NotificationRuleProcessor;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -241,19 +245,7 @@ public class EntityActionService {
} }
} }
if (tenantId != null && !tenantId.isSysTenantId()) { if (tenantId != null && !tenantId.isSysTenantId()) {
if (actionType == ActionType.ADDED) { processNotificationRules(tenantId, entityId, entity, actionType, user, additionalInfo);
notificationRuleProcessor.process(EntitiesLimitTrigger.builder()
.tenantId(tenantId)
.entityType(entityId.getEntityType())
.build());
}
notificationRuleProcessor.process(EntityActionTrigger.builder()
.tenantId(tenantId)
.entityId(entityId)
.entity(entity)
.actionType(actionType)
.user(user)
.build());
} }
TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode));
tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, null); tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, null);
@ -263,6 +255,53 @@ public class EntityActionService {
} }
} }
private void processNotificationRules(TenantId tenantId, EntityId entityId, HasName entity, ActionType actionType, User user, Object... additionalInfo) {
switch (actionType) {
case ADDED:
notificationRuleProcessor.process(EntitiesLimitTrigger.builder()
.tenantId(tenantId)
.entityType(entityId.getEntityType())
.build());
case UPDATED:
case DELETED:
notificationRuleProcessor.process(EntityActionTrigger.builder()
.tenantId(tenantId)
.entityId(entityId)
.entity(entity)
.actionType(actionType)
.user(user)
.build());
break;
case ALARM_ASSIGNED:
case ALARM_UNASSIGNED:
if (!(entity instanceof AlarmInfo)) { // should not normally happen
log.warn("Invalid alarm assignment event: entity is not instance of AlarmInfo");
break;
}
notificationRuleProcessor.process(AlarmAssignmentTrigger.builder()
.tenantId(tenantId)
.alarmInfo((AlarmInfo) entity)
.actionType(actionType)
.user(user)
.build());
break;
case ADDED_COMMENT:
case UPDATED_COMMENT:
if (!(entity instanceof Alarm)) { // should not normally happen
log.warn("Invalid alarm comment event: entity is not instance of Alarm");
break;
}
notificationRuleProcessor.process(AlarmCommentTrigger.builder()
.tenantId(tenantId)
.comment(extractParameter(AlarmComment.class, 0, additionalInfo))
.alarm((Alarm) entity)
.actionType(actionType)
.user(user)
.build());
break;
}
}
public <E extends HasName, I extends EntityId> void logEntityAction(User user, I entityId, E entity, CustomerId customerId, public <E extends HasName, I extends EntityId> void logEntityAction(User user, I entityId, E entity, CustomerId customerId,
ActionType actionType, Exception e, Object... additionalInfo) { ActionType actionType, Exception e, Object... additionalInfo) {
if (customerId == null || customerId.isNullUid()) { if (customerId == null || customerId.isNullUid()) {

39
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java

@ -16,52 +16,48 @@
package org.thingsboard.server.service.notification.rule.trigger; package org.thingsboard.server.service.notification.rule.trigger;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmAssignee; import org.thingsboard.server.common.data.alarm.AlarmAssignee;
import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; import org.thingsboard.server.common.data.alarm.AlarmStatusFilter;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.notification.info.AlarmAssignmentNotificationInfo; import org.thingsboard.server.common.data.notification.info.AlarmAssignmentNotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig.Action; import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig.Action;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineMsgTrigger; import org.thingsboard.server.common.msg.notification.trigger.AlarmAssignmentTrigger;
import java.util.Set;
import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.apache.commons.collections.CollectionUtils.isEmpty;
import static org.thingsboard.server.common.data.util.CollectionsUtil.emptyOrContains; import static org.thingsboard.server.common.data.util.CollectionsUtil.emptyOrContains;
@Service @Service
public class AlarmAssignmentTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<AlarmAssignmentNotificationRuleTriggerConfig> { public class AlarmAssignmentTriggerProcessor implements NotificationRuleTriggerProcessor<AlarmAssignmentTrigger, AlarmAssignmentNotificationRuleTriggerConfig> {
@Override @Override
public boolean matchesFilter(RuleEngineMsgTrigger trigger, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(AlarmAssignmentTrigger trigger, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) {
Action action = trigger.getMsg().getType().equals(DataConstants.ALARM_ASSIGNED) ? Action.ASSIGNED : Action.UNASSIGNED; Action action = trigger.getActionType() == ActionType.ALARM_ASSIGNED ? Action.ASSIGNED : Action.UNASSIGNED;
if (!triggerConfig.getNotifyOn().contains(action)) { if (!triggerConfig.getNotifyOn().contains(action)) {
return false; return false;
} }
Alarm alarm = JacksonUtil.fromString(trigger.getMsg().getData(), Alarm.class); AlarmInfo alarmInfo = trigger.getAlarmInfo();
return emptyOrContains(triggerConfig.getAlarmTypes(), alarm.getType()) && return emptyOrContains(triggerConfig.getAlarmTypes(), alarmInfo.getType()) &&
emptyOrContains(triggerConfig.getAlarmSeverities(), alarm.getSeverity()) && emptyOrContains(triggerConfig.getAlarmSeverities(), alarmInfo.getSeverity()) &&
(isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarm)); (isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarmInfo));
} }
@Override @Override
public RuleOriginatedNotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger) { public RuleOriginatedNotificationInfo constructNotificationInfo(AlarmAssignmentTrigger trigger) {
AlarmInfo alarmInfo = JacksonUtil.fromString(trigger.getMsg().getData(), AlarmInfo.class); AlarmInfo alarmInfo = trigger.getAlarmInfo();
AlarmAssignee assignee = alarmInfo.getAssignee(); AlarmAssignee assignee = alarmInfo.getAssignee();
return AlarmAssignmentNotificationInfo.builder() return AlarmAssignmentNotificationInfo.builder()
.action(trigger.getMsg().getType().equals(DataConstants.ALARM_ASSIGNED) ? "assigned" : "unassigned") .action(trigger.getActionType() == ActionType.ALARM_ASSIGNED ? "assigned" : "unassigned")
.assigneeFirstName(assignee != null ? assignee.getFirstName() : null) .assigneeFirstName(assignee != null ? assignee.getFirstName() : null)
.assigneeLastName(assignee != null ? assignee.getLastName() : null) .assigneeLastName(assignee != null ? assignee.getLastName() : null)
.assigneeEmail(assignee != null ? assignee.getEmail() : null) .assigneeEmail(assignee != null ? assignee.getEmail() : null)
.assigneeId(assignee != null ? assignee.getId() : null) .assigneeId(assignee != null ? assignee.getId() : null)
.userEmail(trigger.getMsg().getMetaData().getValue("userEmail")) .userEmail(trigger.getUser().getEmail())
.userFirstName(trigger.getMsg().getMetaData().getValue("userFirstName")) .userFirstName(trigger.getUser().getFirstName())
.userLastName(trigger.getMsg().getMetaData().getValue("userLastName")) .userLastName(trigger.getUser().getLastName())
.alarmId(alarmInfo.getUuidId()) .alarmId(alarmInfo.getUuidId())
.alarmType(alarmInfo.getType()) .alarmType(alarmInfo.getType())
.alarmOriginator(alarmInfo.getOriginator()) .alarmOriginator(alarmInfo.getOriginator())
@ -77,9 +73,4 @@ public class AlarmAssignmentTriggerProcessor implements RuleEngineMsgNotificatio
return NotificationRuleTriggerType.ALARM_ASSIGNMENT; return NotificationRuleTriggerType.ALARM_ASSIGNMENT;
} }
@Override
public Set<String> getSupportedMsgTypes() {
return Set.of(DataConstants.ALARM_ASSIGNED, DataConstants.ALARM_UNASSIGNED);
}
} }

70
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java

@ -15,68 +15,67 @@
*/ */
package org.thingsboard.server.service.notification.rule.trigger; package org.thingsboard.server.service.notification.rule.trigger;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCommentType; import org.thingsboard.server.common.data.alarm.AlarmCommentType;
import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; import org.thingsboard.server.common.data.alarm.AlarmStatusFilter;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.notification.info.AlarmCommentNotificationInfo; import org.thingsboard.server.common.data.notification.info.AlarmCommentNotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.notification.trigger.AlarmCommentTrigger;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineMsgTrigger; import org.thingsboard.server.dao.entity.EntityService;
import java.util.Set;
import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.apache.commons.collections.CollectionUtils.isEmpty;
import static org.thingsboard.server.common.data.util.CollectionsUtil.emptyOrContains; import static org.thingsboard.server.common.data.util.CollectionsUtil.emptyOrContains;
@Service @Service
public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<AlarmCommentNotificationRuleTriggerConfig> { @RequiredArgsConstructor
public class AlarmCommentTriggerProcessor implements NotificationRuleTriggerProcessor<AlarmCommentTrigger, AlarmCommentNotificationRuleTriggerConfig> {
private final EntityService entityService;
@Override @Override
public boolean matchesFilter(RuleEngineMsgTrigger trigger, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(AlarmCommentTrigger trigger, AlarmCommentNotificationRuleTriggerConfig triggerConfig) {
TbMsg msg = trigger.getMsg(); if (trigger.getActionType() == ActionType.UPDATED_COMMENT && !triggerConfig.isNotifyOnCommentUpdate()) {
if (msg.getMetaData().getValue("comment") == null) {
return false;
}
if (msg.getType().equals(DataConstants.COMMENT_UPDATED) && !triggerConfig.isNotifyOnCommentUpdate()) {
return false; return false;
} }
if (triggerConfig.isOnlyUserComments()) { if (triggerConfig.isOnlyUserComments()) {
AlarmComment comment = JacksonUtil.fromString(msg.getMetaData().getValue("comment"), AlarmComment.class); if (trigger.getComment().getType() == AlarmCommentType.SYSTEM) {
if (comment.getType() == AlarmCommentType.SYSTEM) {
return false; return false;
} }
} }
Alarm alarm = JacksonUtil.fromString(msg.getData(), Alarm.class); Alarm alarm = trigger.getAlarm();
return emptyOrContains(triggerConfig.getAlarmTypes(), alarm.getType()) && return emptyOrContains(triggerConfig.getAlarmTypes(), alarm.getType()) &&
emptyOrContains(triggerConfig.getAlarmSeverities(), alarm.getSeverity()) && emptyOrContains(triggerConfig.getAlarmSeverities(), alarm.getSeverity()) &&
(isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarm)); (isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarm));
} }
@Override @Override
public RuleOriginatedNotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger) { public RuleOriginatedNotificationInfo constructNotificationInfo(AlarmCommentTrigger trigger) {
TbMsg msg = trigger.getMsg(); Alarm alarm = trigger.getAlarm();
AlarmComment comment = JacksonUtil.fromString(msg.getMetaData().getValue("comment"), AlarmComment.class); String originatorName;
AlarmInfo alarmInfo = JacksonUtil.fromString(msg.getData(), AlarmInfo.class); if (alarm instanceof AlarmInfo) {
originatorName = ((AlarmInfo) alarm).getOriginatorName();
} else {
originatorName = entityService.fetchEntityName(trigger.getTenantId(), alarm.getOriginator()).orElse("");
}
return AlarmCommentNotificationInfo.builder() return AlarmCommentNotificationInfo.builder()
.comment(comment.getComment().get("text").asText()) .comment(trigger.getComment().getComment().get("text").asText())
.action(msg.getType().equals(DataConstants.COMMENT_CREATED) ? "added" : "updated") .action(trigger.getActionType() == ActionType.ADDED_COMMENT ? "added" : "updated")
.userEmail(msg.getMetaData().getValue("userEmail")) .userEmail(trigger.getUser().getEmail())
.userFirstName(msg.getMetaData().getValue("userFirstName")) .userFirstName(trigger.getUser().getFirstName())
.userLastName(msg.getMetaData().getValue("userLastName")) .userLastName(trigger.getUser().getLastName())
.alarmId(alarmInfo.getUuidId()) .alarmId(alarm.getUuidId())
.alarmType(alarmInfo.getType()) .alarmType(alarm.getType())
.alarmOriginator(alarmInfo.getOriginator()) .alarmOriginator(alarm.getOriginator())
.alarmOriginatorName(alarmInfo.getOriginatorName()) .alarmOriginatorName(originatorName)
.alarmSeverity(alarmInfo.getSeverity()) .alarmSeverity(alarm.getSeverity())
.alarmStatus(alarmInfo.getStatus()) .alarmStatus(alarm.getStatus())
.alarmCustomerId(alarmInfo.getCustomerId()) .alarmCustomerId(alarm.getCustomerId())
.build(); .build();
} }
@ -85,9 +84,4 @@ public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRu
return NotificationRuleTriggerType.ALARM_COMMENT; return NotificationRuleTriggerType.ALARM_COMMENT;
} }
@Override
public Set<String> getSupportedMsgTypes() {
return Set.of(DataConstants.COMMENT_CREATED, DataConstants.COMMENT_UPDATED);
}
} }

38
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceActivityTriggerProcessor.java

@ -18,9 +18,7 @@ package org.thingsboard.server.service.notification.rule.trigger;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.info.DeviceActivityNotificationInfo; import org.thingsboard.server.common.data.notification.info.DeviceActivityNotificationInfo;
@ -28,28 +26,22 @@ import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotifi
import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent; import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.notification.trigger.DeviceActivityTrigger;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import java.util.Set;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class DeviceActivityTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<DeviceActivityNotificationRuleTriggerConfig> { public class DeviceActivityTriggerProcessor implements NotificationRuleTriggerProcessor<DeviceActivityTrigger, DeviceActivityNotificationRuleTriggerConfig> {
private final TbDeviceProfileCache deviceProfileCache; private final TbDeviceProfileCache deviceProfileCache;
@Override @Override
public boolean matchesFilter(RuleEngineMsgTrigger trigger, DeviceActivityNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(DeviceActivityTrigger trigger, DeviceActivityNotificationRuleTriggerConfig triggerConfig) {
if (trigger.getMsg().getOriginator().getEntityType() != EntityType.DEVICE) { DeviceEvent event = trigger.isActive() ? DeviceEvent.ACTIVE : DeviceEvent.INACTIVE;
return false;
}
DeviceEvent event = trigger.getMsg().getType().equals(DataConstants.ACTIVITY_EVENT) ? DeviceEvent.ACTIVE : DeviceEvent.INACTIVE;
if (!triggerConfig.getNotifyOn().contains(event)) { if (!triggerConfig.getNotifyOn().contains(event)) {
return false; return false;
} }
DeviceId deviceId = (DeviceId) trigger.getMsg().getOriginator(); DeviceId deviceId = trigger.getDeviceId();
if (CollectionUtils.isNotEmpty(triggerConfig.getDevices())) { if (CollectionUtils.isNotEmpty(triggerConfig.getDevices())) {
return triggerConfig.getDevices().contains(deviceId.getId()); return triggerConfig.getDevices().contains(deviceId.getId());
} else if (CollectionUtils.isNotEmpty(triggerConfig.getDeviceProfiles())) { } else if (CollectionUtils.isNotEmpty(triggerConfig.getDeviceProfiles())) {
@ -61,15 +53,14 @@ public class DeviceActivityTriggerProcessor implements RuleEngineMsgNotification
} }
@Override @Override
public RuleOriginatedNotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger) { public RuleOriginatedNotificationInfo constructNotificationInfo(DeviceActivityTrigger trigger) {
TbMsg msg = trigger.getMsg();
return DeviceActivityNotificationInfo.builder() return DeviceActivityNotificationInfo.builder()
.eventType(trigger.getMsg().getType().equals(DataConstants.ACTIVITY_EVENT) ? "active" : "inactive") .eventType(trigger.isActive() ? "active" : "inactive")
.deviceId(msg.getOriginator().getId()) .deviceId(trigger.getDeviceId().getId())
.deviceName(msg.getMetaData().getValue("deviceName")) .deviceName(trigger.getDeviceName())
.deviceType(msg.getMetaData().getValue("deviceType")) .deviceType(trigger.getDeviceType())
.deviceLabel(msg.getMetaData().getValue("deviceLabel")) .deviceLabel(trigger.getDeviceLabel())
.deviceCustomerId(msg.getCustomerId()) .deviceCustomerId(trigger.getCustomerId())
.build(); .build();
} }
@ -78,9 +69,4 @@ public class DeviceActivityTriggerProcessor implements RuleEngineMsgNotification
return NotificationRuleTriggerType.DEVICE_ACTIVITY; return NotificationRuleTriggerType.DEVICE_ACTIVITY;
} }
@Override
public Set<String> getSupportedMsgTypes() {
return Set.of(DataConstants.ACTIVITY_EVENT, DataConstants.INACTIVITY_EVENT);
}
} }

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

@ -31,7 +31,6 @@ import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.common.util.ThingsBoardExecutors;
@ -63,6 +62,8 @@ import org.thingsboard.server.common.data.query.EntityListFilter;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.msg.notification.trigger.DeviceActivityTrigger;
import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
@ -70,12 +71,10 @@ import org.thingsboard.server.common.stats.TbApiUsageReportClient;
import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.sql.query.EntityQueryRepository; import org.thingsboard.server.dao.sql.query.EntityQueryRepository;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.dao.util.DbTypeInfoComponent; import org.thingsboard.server.dao.util.DbTypeInfoComponent;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.partition.AbstractPartitionBasedService; import org.thingsboard.server.service.partition.AbstractPartitionBasedService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
@ -158,6 +157,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
private final EntityQueryRepository entityQueryRepository; private final EntityQueryRepository entityQueryRepository;
private final DbTypeInfoComponent dbTypeInfoComponent; private final DbTypeInfoComponent dbTypeInfoComponent;
private final TbApiUsageReportClient apiUsageReportClient; private final TbApiUsageReportClient apiUsageReportClient;
private final NotificationRuleProcessor notificationRuleProcessor;
@Autowired @Lazy @Autowired @Lazy
private TelemetrySubscriptionService tsSubService; private TelemetrySubscriptionService tsSubService;
@ -254,8 +254,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
state.setLastActivityTime(lastReportedActivity); state.setLastActivityTime(lastReportedActivity);
if (!state.isActive()) { if (!state.isActive()) {
state.setActive(true); state.setActive(true);
save(deviceId, ACTIVITY_STATE, true); onDeviceActivityStatusChange(deviceId, true, stateData);
pushRuleEngineMessage(stateData, ACTIVITY_EVENT);
} }
} else { } else {
log.debug("updateActivityState - fetched state IN NULL for device {}, lastReportedActivity {}", deviceId, lastReportedActivity); log.debug("updateActivityState - fetched state IN NULL for device {}, lastReportedActivity {}", deviceId, lastReportedActivity);
@ -491,9 +490,8 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
if (partitionService.resolve(ServiceType.TB_CORE, stateData.getTenantId(), deviceId).isMyPartition()) { if (partitionService.resolve(ServiceType.TB_CORE, stateData.getTenantId(), deviceId).isMyPartition()) {
state.setActive(false); state.setActive(false);
state.setLastInactivityAlarmTime(ts); state.setLastInactivityAlarmTime(ts);
save(deviceId, ACTIVITY_STATE, false); onDeviceActivityStatusChange(deviceId, false, stateData);
save(deviceId, INACTIVITY_ALARM_TIME, ts); save(deviceId, INACTIVITY_ALARM_TIME, ts);
pushRuleEngineMessage(stateData, INACTIVITY_EVENT);
} else { } else {
cleanupEntity(deviceId); cleanupEntity(deviceId);
} }
@ -533,6 +531,19 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
} }
} }
private void onDeviceActivityStatusChange(DeviceId deviceId, boolean active, DeviceStateData stateData) {
save(deviceId, ACTIVITY_STATE, active);
pushRuleEngineMessage(stateData, active ? ACTIVITY_EVENT : INACTIVITY_EVENT);
TbMsgMetaData metaData = stateData.getMetaData();
notificationRuleProcessor.process(DeviceActivityTrigger.builder()
.tenantId(stateData.getTenantId()).customerId(stateData.getCustomerId())
.deviceId(deviceId).active(active)
.deviceName(metaData.getValue("deviceName"))
.deviceType(metaData.getValue("deviceType"))
.deviceLabel(metaData.getValue("deviceLabel"))
.build());
}
private boolean cleanDeviceStateIfBelongsExternalPartition(TenantId tenantId, final DeviceId deviceId) { private boolean cleanDeviceStateIfBelongsExternalPartition(TenantId tenantId, final DeviceId deviceId) {
TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId); TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId);
boolean cleanup = !partitionedEntities.containsKey(tpi); boolean cleanup = !partitionedEntities.containsKey(tpi);

6
application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java

@ -29,12 +29,11 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityData;
import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.EntityKeyType;
import org.thingsboard.server.common.data.query.TsValue; import org.thingsboard.server.common.data.query.TsValue;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@ -42,6 +41,7 @@ import java.util.UUID;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.BDDMockito.willReturn; import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
@ -69,7 +69,7 @@ public class DefaultDeviceStateServiceTest {
@Before @Before
public void setUp() { public void setUp() {
service = spy(new DefaultDeviceStateService(deviceService, attributesService, tsService, clusterService, partitionService, null, null, null)); service = spy(new DefaultDeviceStateService(deviceService, attributesService, tsService, clusterService, partitionService, null, null, null, mock(NotificationRuleProcessor.class)));
} }
@Test @Test

22
common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/RuleEngineMsgTrigger.java → common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmAssignmentTrigger.java

@ -17,30 +17,30 @@ package org.thingsboard.server.common.msg.notification.trigger;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.TbMsg;
import java.util.Map;
@Data @Data
@Builder @Builder
public class RuleEngineMsgTrigger implements NotificationRuleTrigger { public class AlarmAssignmentTrigger implements NotificationRuleTrigger {
private final TenantId tenantId; private final TenantId tenantId;
private final TbMsg msg; private final AlarmInfo alarmInfo;
private final ActionType actionType;
public static Map<String, NotificationRuleTriggerType> msgTypeToTriggerType; // set on init by DefaultNotificationRuleProcessor private final User user;
@Override @Override
public NotificationRuleTriggerType getType() { public EntityId getOriginatorEntityId() {
return msgTypeToTriggerType != null ? msgTypeToTriggerType.get(msg.getType()) : null; return alarmInfo.getOriginator();
} }
@Override @Override
public EntityId getOriginatorEntityId() { public NotificationRuleTriggerType getType() {
return msg.getOriginator(); return NotificationRuleTriggerType.ALARM_ASSIGNMENT;
} }
} }

48
common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmCommentTrigger.java

@ -0,0 +1,48 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.msg.notification.trigger;
import lombok.Builder;
import lombok.Data;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
@Data
@Builder
public class AlarmCommentTrigger implements NotificationRuleTrigger {
private final TenantId tenantId;
private final AlarmComment comment;
private final Alarm alarm;
private final ActionType actionType;
private final User user;
@Override
public NotificationRuleTriggerType getType() {
return NotificationRuleTriggerType.ALARM_COMMENT;
}
@Override
public EntityId getOriginatorEntityId() {
return alarm.getId();
}
}

5
common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/ApiUsageLimitTrigger.java

@ -36,11 +36,6 @@ public class ApiUsageLimitTrigger implements NotificationRuleTrigger {
return NotificationRuleTriggerType.API_USAGE_LIMIT; return NotificationRuleTriggerType.API_USAGE_LIMIT;
} }
@Override
public TenantId getTenantId() {
return tenantId;
}
@Override @Override
public EntityId getOriginatorEntityId() { public EntityId getOriginatorEntityId() {
return tenantId; return tenantId;

49
common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/DeviceActivityTrigger.java

@ -0,0 +1,49 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.msg.notification.trigger;
import lombok.Builder;
import lombok.Data;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
@Data
@Builder
public class DeviceActivityTrigger implements NotificationRuleTrigger {
private final TenantId tenantId;
private final CustomerId customerId;
private final DeviceId deviceId;
private final boolean active;
private final String deviceName;
private final String deviceType;
private final String deviceLabel;
@Override
public EntityId getOriginatorEntityId() {
return deviceId;
}
@Override
public NotificationRuleTriggerType getType() {
return NotificationRuleTriggerType.DEVICE_ACTIVITY;
}
}
Loading…
Cancel
Save