diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java index f23acbc0db..327478367b 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java @@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import org.thingsboard.server.dao.notification.trigger.RuleEngineComponentLifecycleEventTrigger; public abstract class RuleEngineComponentActor> extends ComponentActor { @@ -32,8 +33,14 @@ public abstract class RuleEngineComponentActor implements TbApiUsageStateService { public static final String HOURLY = "Hourly"; @@ -105,6 +108,7 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService private final ApiUsageStateService apiUsageStateService; private final TbTenantProfileCache tenantProfileCache; private final MailService mailService; + private final NotificationRuleProcessingService notificationRuleProcessingService; private final DbCallbackExecutorService dbExecutor; @Lazy @@ -126,26 +130,7 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService private final Lock updateLock = new ReentrantLock(); - private final ExecutorService mailExecutor; - - public DefaultTbApiUsageStateService(TbClusterService clusterService, - PartitionService partitionService, - TenantService tenantService, - TimeseriesService tsService, - ApiUsageStateService apiUsageStateService, - TbTenantProfileCache tenantProfileCache, - MailService mailService, - DbCallbackExecutorService dbExecutor) { - this.clusterService = clusterService; - this.partitionService = partitionService; - this.tenantService = tenantService; - this.tsService = tsService; - this.apiUsageStateService = apiUsageStateService; - this.tenantProfileCache = tenantProfileCache; - this.mailService = mailService; - this.mailExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("api-usage-svc-mail")); - this.dbExecutor = dbExecutor; - } + private final ExecutorService mailExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("api-usage-svc-mail")); @PostConstruct public void init() { @@ -355,6 +340,7 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK); if (state.getEntityType() == EntityType.TENANT && !state.getEntityId().equals(TenantId.SYS_TENANT_ID)) { + String email = tenantService.findTenantById(state.getTenantId()).getEmail(); if (StringUtils.isNotEmpty(email)) { result.forEach((apiFeature, stateValue) -> { diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java index b197816a8f..682c97ede2 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java @@ -23,29 +23,27 @@ import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.thingsboard.rule.engine.api.NotificationCenter; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.NotificationRequestId; import org.thingsboard.server.common.data.id.NotificationRuleId; -import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.NotificationRequest; import org.thingsboard.server.common.data.notification.NotificationRequestConfig; import org.thingsboard.server.common.data.notification.NotificationRequestStatus; import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.rule.NotificationRule; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; -import org.thingsboard.server.dao.alarm.AlarmApiCallResult; import org.thingsboard.server.dao.notification.NotificationRequestService; import org.thingsboard.server.dao.notification.NotificationRuleProcessingService; import org.thingsboard.server.dao.notification.NotificationRuleService; +import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger; import org.thingsboard.server.service.executors.NotificationExecutorService; import org.thingsboard.server.service.notification.rule.trigger.NotificationRuleTriggerProcessor; -import org.thingsboard.server.service.notification.rule.trigger.RuleEngineComponentLifecycleEventTriggerProcessor.RuleEngineComponentLifecycleEventTriggerObject; import org.thingsboard.server.service.notification.rule.trigger.RuleEngineMsgNotificationRuleTriggerProcessor; import java.util.Collection; @@ -60,7 +58,7 @@ import java.util.stream.Collectors; @Service @RequiredArgsConstructor @Slf4j -@SuppressWarnings("rawtypes") +@SuppressWarnings({"rawtypes", "unchecked"}) public class DefaultNotificationRuleProcessingService implements NotificationRuleProcessingService { private final NotificationRuleService notificationRuleService; @@ -74,80 +72,37 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul private final Map ruleEngineMsgTypeToTriggerType = new HashMap<>(); @Override - public void process(TenantId tenantId, TbMsg ruleEngineMsg) { - String msgType = ruleEngineMsg.getType(); - NotificationRuleTriggerType triggerType = ruleEngineMsgTypeToTriggerType.get(msgType); - if (triggerType == null) { - return; - } - processTrigger(tenantId, triggerType, ruleEngineMsg.getOriginator(), ruleEngineMsg); - } - - @Override - public void process(TenantId tenantId, AlarmApiCallResult alarmUpdate) { - processTrigger(tenantId, NotificationRuleTriggerType.ALARM, alarmUpdate.getAlarm().getId(), alarmUpdate); - } - - @Override - public void process(TenantId tenantId, RuleChainId ruleChainId, String ruleChainName, EntityId componentId, String componentName, ComponentLifecycleEvent eventType, Exception error) { - RuleEngineComponentLifecycleEventTriggerObject triggerObject = RuleEngineComponentLifecycleEventTriggerObject.builder() - .ruleChainId(ruleChainId) - .ruleChainName(ruleChainName) - .componentId(componentId) - .componentName(componentName) - .eventType(eventType) - .error(error) - .build(); - processTrigger(tenantId, NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, componentId, triggerObject); - } - - @Override - public void process(UpdateMessage platformUpdateMessage) { -// if (!partitionService.resolve(ServiceType.TB_CORE, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isMyPartition()) { -// return; -// } -// // todo: don't send repetitive notification after platform restart? -// -// processTrigger(TenantId.SYS_TENANT_ID, NotificationRuleTriggerType.NEW_PLATFORM_VERSION, TenantId.SYS_TENANT_ID, platformUpdateMessage); - } - - @Override - public void process(TenantId tenantId, EntityType entityType, long limit, long currentCount) { -// EntitiesLimitTriggerObject triggerObject = EntitiesLimitTriggerObject.builder() -// .entityType(entityType) -// .limit(limit) -// .currentCount(currentCount) -// .build(); - } - - @Override - public void process(ComponentLifecycleMsg componentLifecycleMsg) { -// EntityId entityId = componentLifecycleMsg.getEntityId(); -// switch (entityId.getEntityType()) { -// case TENANT: -// -// } - } - - private void processTrigger(TenantId tenantId, NotificationRuleTriggerType triggerType, EntityId originatorEntityId, Object triggerObject) { - List rules = notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, triggerType); + public void process(TenantId tenantId, NotificationRuleTrigger trigger) { + List rules = notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, trigger.getType()); for (NotificationRule rule : rules) { notificationExecutor.submit(() -> { try { - processNotificationRule(rule, originatorEntityId, triggerObject); + processNotificationRule(rule, trigger); } catch (Throwable e) { - log.error("Failed to process notification rule {} for trigger type {} with trigger object {}", rule.getId(), rule.getTriggerType(), triggerObject, e); + log.error("Failed to process notification rule {} for trigger type {} with trigger object {}", rule.getId(), rule.getTriggerType(), trigger, e); } }); } } - private void processNotificationRule(NotificationRule rule, EntityId originatorEntityId, Object triggerObject) { + @Override + public void process(TenantId tenantId, TbMsg ruleEngineMsg) { + NotificationRuleTriggerType triggerType = ruleEngineMsgTypeToTriggerType.get(ruleEngineMsg.getType()); + if (triggerType == null) { + return; + } + process(tenantId, RuleEngineMsgTrigger.builder() + .msg(ruleEngineMsg) + .triggerType(triggerType) + .build()); + } + + private void processNotificationRule(NotificationRule rule, NotificationRuleTrigger trigger) { NotificationRuleTriggerConfig triggerConfig = rule.getTriggerConfig(); log.debug("Processing notification rule '{}' for trigger type {}", rule.getName(), rule.getTriggerType()); - if (matchesClearRule(triggerObject, triggerConfig)) { - List notificationRequests = notificationRequestService.findNotificationRequestsByRuleIdAndOriginatorEntityId(rule.getTenantId(), rule.getId(), originatorEntityId); + if (matchesClearRule(trigger, triggerConfig)) { + List notificationRequests = notificationRequestService.findNotificationRequestsByRuleIdAndOriginatorEntityId(rule.getTenantId(), rule.getId(), trigger.getOriginatorEntityId()); if (notificationRequests.isEmpty()) { return; } @@ -156,8 +111,8 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul .filter(NotificationRequest::isSent) .flatMap(notificationRequest -> notificationRequest.getTargets().stream()) .distinct().collect(Collectors.toList()); - NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); - submitNotificationRequest(targets, rule, originatorEntityId, notificationInfo, 0); + NotificationInfo notificationInfo = constructNotificationInfo(trigger, triggerConfig); + submitNotificationRequest(targets, rule, trigger.getOriginatorEntityId(), notificationInfo, 0); notificationRequests.forEach(notificationRequest -> { if (notificationRequest.isScheduled()) { @@ -167,24 +122,24 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul return; } - if (matchesFilter(triggerObject, triggerConfig)) { - NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); + if (matchesFilter(trigger, triggerConfig)) { + NotificationInfo notificationInfo = constructNotificationInfo(trigger, triggerConfig); rule.getRecipientsConfig().getTargetsTable().forEach((delay, targets) -> { - submitNotificationRequest(targets, rule, originatorEntityId, notificationInfo, delay); + submitNotificationRequest(targets, rule, trigger.getOriginatorEntityId(), notificationInfo, delay); }); } } - private boolean matchesFilter(Object triggerObject, NotificationRuleTriggerConfig triggerConfig) { - return triggerProcessors.get(triggerConfig.getTriggerType()).matchesFilter(triggerObject, triggerConfig); + private boolean matchesFilter(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) { + return triggerProcessors.get(triggerConfig.getTriggerType()).matchesFilter(trigger, triggerConfig); } - private boolean matchesClearRule(Object triggerObject, NotificationRuleTriggerConfig triggerConfig) { - return triggerProcessors.get(triggerConfig.getTriggerType()).matchesClearRule(triggerObject, triggerConfig); + private boolean matchesClearRule(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) { + return triggerProcessors.get(triggerConfig.getTriggerType()).matchesClearRule(trigger, triggerConfig); } - private NotificationInfo constructNotificationInfo(Object triggerObject, NotificationRuleTriggerConfig triggerConfig) { - return triggerProcessors.get(triggerConfig.getTriggerType()).constructNotificationInfo(triggerObject, triggerConfig); + private NotificationInfo constructNotificationInfo(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) { + return triggerProcessors.get(triggerConfig.getTriggerType()).constructNotificationInfo(trigger, triggerConfig); } private void submitNotificationRequest(List targets, NotificationRule rule, diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java index bda6800e34..9fd0c06118 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.notification.info.NotificationInfo; 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.NotificationRuleTriggerType; -import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger; import java.util.Set; @@ -37,28 +37,28 @@ import static org.apache.commons.collections.CollectionUtils.isEmpty; public class AlarmAssignmentTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor { @Override - public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { - Action action = ruleEngineMsg.getType().equals(DataConstants.ALARM_ASSIGN) ? Action.ASSIGNED : Action.UNASSIGNED; + public boolean matchesFilter(RuleEngineMsgTrigger trigger, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { + Action action = trigger.getMsg().getType().equals(DataConstants.ALARM_ASSIGN) ? Action.ASSIGNED : Action.UNASSIGNED; if (!triggerConfig.getNotifyOn().contains(action)) { return false; } - Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class); + Alarm alarm = JacksonUtil.fromString(trigger.getMsg().getData(), Alarm.class); return (isEmpty(triggerConfig.getAlarmTypes()) || triggerConfig.getAlarmTypes().contains(alarm.getType())) && (isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())) && (isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarm)); } @Override - public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { - AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class); + public NotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { + AlarmInfo alarmInfo = JacksonUtil.fromString(trigger.getMsg().getData(), AlarmInfo.class); AlarmAssignee assignee = alarmInfo.getAssignee(); return AlarmAssignmentNotificationInfo.builder() - .action(ruleEngineMsg.getType().equals(DataConstants.ALARM_ASSIGN) ? "assigned" : "unassigned") + .action(trigger.getMsg().getType().equals(DataConstants.ALARM_ASSIGN) ? "assigned" : "unassigned") .assigneeFirstName(assignee != null ? assignee.getFirstName() : null) .assigneeLastName(assignee != null ? assignee.getLastName() : null) .assigneeEmail(assignee != null ? assignee.getEmail() : null) .assigneeId(assignee != null ? assignee.getId() : null) - .userName(ruleEngineMsg.getMetaData().getValue("userName")) + .userName(trigger.getMsg().getMetaData().getValue("userName")) .alarmId(alarmInfo.getUuidId()) .alarmType(alarmInfo.getType()) .alarmOriginator(alarmInfo.getOriginator()) diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java index d389f22960..0250f0929f 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.notification.info.NotificationInfo; 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.msg.TbMsg; +import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger; import java.util.Set; @@ -37,33 +38,35 @@ import static org.apache.commons.collections.CollectionUtils.isEmpty; public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor { @Override - public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { - if (ruleEngineMsg.getMetaData().getValue("comment") == null) { + public boolean matchesFilter(RuleEngineMsgTrigger trigger, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { + TbMsg msg = trigger.getMsg(); + if (msg.getMetaData().getValue("comment") == null) { return false; } - if (ruleEngineMsg.getType().equals(DataConstants.COMMENT_UPDATED) && !triggerConfig.isNotifyOnCommentUpdate()) { + if (msg.getType().equals(DataConstants.COMMENT_UPDATED) && !triggerConfig.isNotifyOnCommentUpdate()) { return false; } if (triggerConfig.isOnlyUserComments()) { - AlarmComment comment = JacksonUtil.fromString(ruleEngineMsg.getMetaData().getValue("comment"), AlarmComment.class); + AlarmComment comment = JacksonUtil.fromString(msg.getMetaData().getValue("comment"), AlarmComment.class); if (comment.getType() == AlarmCommentType.SYSTEM) { return false; } } - Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class); + Alarm alarm = JacksonUtil.fromString(msg.getData(), Alarm.class); return (isEmpty(triggerConfig.getAlarmTypes()) || triggerConfig.getAlarmTypes().contains(alarm.getType())) && (isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())) && (isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarm)); } @Override - public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { - AlarmComment comment = JacksonUtil.fromString(ruleEngineMsg.getMetaData().getValue("comment"), AlarmComment.class); - AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class); + public NotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { + TbMsg msg = trigger.getMsg(); + AlarmComment comment = JacksonUtil.fromString(msg.getMetaData().getValue("comment"), AlarmComment.class); + AlarmInfo alarmInfo = JacksonUtil.fromString(msg.getData(), AlarmInfo.class); return AlarmCommentNotificationInfo.builder() .comment(comment.getComment().get("text").asText()) - .action(ruleEngineMsg.getType().equals(DataConstants.COMMENT_CREATED) ? "added" : "updated") - .userName(ruleEngineMsg.getMetaData().getValue("userName")) + .action(msg.getType().equals(DataConstants.COMMENT_CREATED) ? "added" : "updated") + .userName(msg.getMetaData().getValue("userName")) .alarmId(alarmInfo.getUuidId()) .alarmType(alarmInfo.getType()) .alarmOriginator(alarmInfo.getOriginator()) diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java index 31af9e2333..085fb02bbc 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java @@ -26,15 +26,17 @@ import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotific import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.ClearRule; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.dao.alarm.AlarmApiCallResult; +import org.thingsboard.server.dao.notification.trigger.AlarmTrigger; import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.apache.commons.collections.CollectionUtils.isNotEmpty; @Service -public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor { +public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor { @Override - public boolean matchesFilter(AlarmApiCallResult alarmUpdate, AlarmNotificationRuleTriggerConfig triggerConfig) { + public boolean matchesFilter(AlarmTrigger trigger, AlarmNotificationRuleTriggerConfig triggerConfig) { + AlarmApiCallResult alarmUpdate = trigger.getAlarmUpdate(); Alarm alarm = alarmUpdate.getAlarm(); if (!typeMatches(alarm, triggerConfig)) { return false; @@ -64,7 +66,8 @@ public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor { +public class EntitiesLimitTriggerProcessor implements NotificationRuleTriggerProcessor { @Override - public boolean matchesFilter(EntitiesLimitTriggerObject triggerObject, EntitiesLimitNotificationRuleTriggerConfig triggerConfig) { - if (isNotEmpty(triggerConfig.getEntityTypes()) && !triggerConfig.getEntityTypes().contains(triggerObject.getEntityType())) { + public boolean matchesFilter(EntitiesLimitTrigger trigger, EntitiesLimitNotificationRuleTriggerConfig triggerConfig) { + if (isNotEmpty(triggerConfig.getEntityTypes()) && !triggerConfig.getEntityTypes().contains(trigger.getEntityType())) { return false; } - return ((float) triggerObject.getCurrentCount() / triggerObject.getLimit()) >= triggerConfig.getThreshold(); + return (int) (trigger.getLimit() * triggerConfig.getThreshold()) == trigger.getCurrentCount(); // strict comparing not to send notification on each new entity } @Override - public NotificationInfo constructNotificationInfo(EntitiesLimitTriggerObject triggerObject, EntitiesLimitNotificationRuleTriggerConfig triggerConfig) { + public NotificationInfo constructNotificationInfo(EntitiesLimitTrigger trigger, EntitiesLimitNotificationRuleTriggerConfig triggerConfig) { return EntitiesLimitNotificationInfo.builder() - .entityType(triggerObject.getEntityType()) - .threshold((int) (triggerConfig.getThreshold() * 100)) + .entityType(trigger.getEntityType()) + .currentCount(trigger.getCurrentCount()) + .limit(trigger.getLimit()) + .percents((int) (((float)trigger.getCurrentCount() / trigger.getLimit()) * 100)) .build(); } @@ -51,12 +50,4 @@ public class EntitiesLimitTriggerProcessor implements NotificationRuleTriggerPro return NotificationRuleTriggerType.ENTITIES_LIMIT; } - @Data - @Builder - public static class EntitiesLimitTriggerObject { - private final EntityType entityType; - private final long limit; - private final long currentCount; - } - } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java index 54f1db5728..bcace461f5 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java @@ -19,12 +19,12 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.audit.ActionType; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.notification.info.EntityActionNotificationInfo; import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger; import java.util.Optional; import java.util.Set; @@ -34,8 +34,8 @@ import java.util.UUID; public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor { @Override - public boolean matchesFilter(TbMsg ruleEngineMsg, EntityActionNotificationRuleTriggerConfig triggerConfig) { - String msgType = ruleEngineMsg.getType(); + public boolean matchesFilter(RuleEngineMsgTrigger trigger, EntityActionNotificationRuleTriggerConfig triggerConfig) { + String msgType = trigger.getMsg().getType(); if (msgType.equals(DataConstants.ENTITY_CREATED)) { if (!triggerConfig.isCreated()) { return false; @@ -51,28 +51,28 @@ public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRu } else { return false; } - return triggerConfig.getEntityType() == null || getEntityType(ruleEngineMsg) == triggerConfig.getEntityType(); + return triggerConfig.getEntityType() == null || getEntityType(trigger.getMsg()) == triggerConfig.getEntityType(); } @Override - public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, EntityActionNotificationRuleTriggerConfig triggerConfig) { - EntityId entityId = ruleEngineMsg.getOriginator(); - String msgType = ruleEngineMsg.getType(); + public NotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger, EntityActionNotificationRuleTriggerConfig triggerConfig) { + TbMsg msg = trigger.getMsg(); + String msgType = msg.getType(); ActionType actionType = msgType.equals(DataConstants.ENTITY_CREATED) ? ActionType.ADDED : msgType.equals(DataConstants.ENTITY_UPDATED) ? ActionType.UPDATED : msgType.equals(DataConstants.ENTITY_DELETED) ? ActionType.DELETED : null; return EntityActionNotificationInfo.builder() - .entityId(actionType != ActionType.DELETED ? entityId : null) - .entityName(ruleEngineMsg.getMetaData().getValue("entityName")) + .entityId(actionType != ActionType.DELETED ? msg.getOriginator() : null) + .entityName(msg.getMetaData().getValue("entityName")) .actionType(actionType) - .originatorUserId(UUID.fromString(ruleEngineMsg.getMetaData().getValue("userId"))) - .originatorUserName(ruleEngineMsg.getMetaData().getValue("userName")) - .entityCustomerId(ruleEngineMsg.getCustomerId()) + .originatorUserId(UUID.fromString(msg.getMetaData().getValue("userId"))) + .originatorUserName(msg.getMetaData().getValue("userName")) + .entityCustomerId(msg.getCustomerId()) .build(); } - private static EntityType getEntityType(TbMsg ruleEngineMsg) { - return Optional.ofNullable(ruleEngineMsg.getMetaData().getValue("entityType")) + private static EntityType getEntityType(TbMsg msg) { + return Optional.ofNullable(msg.getMetaData().getValue("entityType")) .map(EntityType::valueOf).orElse(null); } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java index e26328404b..ba346caab8 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java @@ -15,25 +15,36 @@ */ package org.thingsboard.server.service.notification.rule.trigger; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.UpdateMessage; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.info.NewPlatformVersionNotificationInfo; import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionTrigger; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.msg.queue.ServiceType; +import org.thingsboard.server.queue.discovery.PartitionService; @Service -public class NewPlatformVersionTriggerProcessor implements NotificationRuleTriggerProcessor { +@RequiredArgsConstructor +public class NewPlatformVersionTriggerProcessor implements NotificationRuleTriggerProcessor { + + private final PartitionService partitionService; @Override - public boolean matchesFilter(UpdateMessage triggerObject, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) { - return triggerObject.isUpdateAvailable(); + public boolean matchesFilter(NewPlatformVersionTrigger trigger, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) { + // todo: don't send repetitive notification after platform restart? + if (!partitionService.resolve(ServiceType.TB_CORE, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isMyPartition()) { + return false; + } + return trigger.getMessage().isUpdateAvailable(); } @Override - public NotificationInfo constructNotificationInfo(UpdateMessage updateMessage, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) { + public NotificationInfo constructNotificationInfo(NewPlatformVersionTrigger trigger, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) { return NewPlatformVersionNotificationInfo.builder() - .message(updateMessage.getMessage()) + .message(trigger.getMessage().getMessage()) .build(); } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java index 4980906f7a..bb24f66d87 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java @@ -16,18 +16,19 @@ package org.thingsboard.server.service.notification.rule.trigger; import org.thingsboard.server.common.data.notification.info.NotificationInfo; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -public interface NotificationRuleTriggerProcessor { +public interface NotificationRuleTriggerProcessor { - boolean matchesFilter(T triggerObject, C triggerConfig); + boolean matchesFilter(T trigger, C triggerConfig); - default boolean matchesClearRule(T triggerObject, C triggerConfig) { + default boolean matchesClearRule(T trigger, C triggerConfig) { return false; } - NotificationInfo constructNotificationInfo(T triggerObject, C triggerConfig); + NotificationInfo constructNotificationInfo(T trigger, C triggerConfig); NotificationRuleTriggerType getTriggerType(); diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java index 123eb8e6f7..b31371e9be 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java @@ -15,39 +15,34 @@ */ package org.thingsboard.server.service.notification.rule.trigger; -import com.google.common.base.Strings; -import lombok.Builder; -import lombok.Data; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleEngineComponentLifecycleEventNotificationInfo; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; -import org.thingsboard.server.service.notification.rule.trigger.RuleEngineComponentLifecycleEventTriggerProcessor.RuleEngineComponentLifecycleEventTriggerObject; +import org.thingsboard.server.dao.notification.trigger.RuleEngineComponentLifecycleEventTrigger; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Set; @Service -public class RuleEngineComponentLifecycleEventTriggerProcessor implements NotificationRuleTriggerProcessor { +public class RuleEngineComponentLifecycleEventTriggerProcessor implements NotificationRuleTriggerProcessor { @Override - public boolean matchesFilter(RuleEngineComponentLifecycleEventTriggerObject triggerObject, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) { + public boolean matchesFilter(RuleEngineComponentLifecycleEventTrigger trigger, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) { if (CollectionUtils.isNotEmpty(triggerConfig.getRuleChains())) { - if (!triggerConfig.getRuleChains().contains(triggerObject.getRuleChainId().getId())) { + if (!triggerConfig.getRuleChains().contains(trigger.getRuleChainId().getId())) { return false; } } - EntityType componentType = triggerObject.getComponentId().getEntityType(); + EntityType componentType = trigger.getComponentId().getEntityType(); Set trackedEvents; boolean onlyFailures; if (componentType == EntityType.RULE_CHAIN) { @@ -63,27 +58,27 @@ public class RuleEngineComponentLifecycleEventTriggerProcessor implements Notifi trackedEvents = Set.of(ComponentLifecycleEvent.STARTED, ComponentLifecycleEvent.UPDATED, ComponentLifecycleEvent.STOPPED); } - if (!trackedEvents.contains(triggerObject.getEventType())) { + if (!trackedEvents.contains(trigger.getEventType())) { return false; } if (onlyFailures) { - return triggerObject.getError() != null; + return trigger.getError() != null; } return true; } @Override - public NotificationInfo constructNotificationInfo(RuleEngineComponentLifecycleEventTriggerObject triggerObject, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) { + public NotificationInfo constructNotificationInfo(RuleEngineComponentLifecycleEventTrigger trigger, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) { return RuleEngineComponentLifecycleEventNotificationInfo.builder() - .ruleChainId(triggerObject.getRuleChainId()) - .ruleChainName(triggerObject.getRuleChainName()) - .componentId(triggerObject.getComponentId()) - .componentName(triggerObject.getComponentName()) - .action(triggerObject.getEventType() == ComponentLifecycleEvent.STARTED ? "start" : - triggerObject.getEventType() == ComponentLifecycleEvent.UPDATED ? "update" : - triggerObject.getEventType() == ComponentLifecycleEvent.STOPPED ? "stop" : null) - .eventType(triggerObject.getEventType()) - .error(getErrorMsg(triggerObject.getError())) + .ruleChainId(trigger.getRuleChainId()) + .ruleChainName(trigger.getRuleChainName()) + .componentId(trigger.getComponentId()) + .componentName(trigger.getComponentName()) + .action(trigger.getEventType() == ComponentLifecycleEvent.STARTED ? "start" : + trigger.getEventType() == ComponentLifecycleEvent.UPDATED ? "update" : + trigger.getEventType() == ComponentLifecycleEvent.STOPPED ? "stop" : null) + .eventType(trigger.getEventType()) + .error(getErrorMsg(trigger.getError())) .build(); } @@ -100,15 +95,4 @@ public class RuleEngineComponentLifecycleEventTriggerProcessor implements Notifi return NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT; } - @Data - @Builder - public static class RuleEngineComponentLifecycleEventTriggerObject { - private final RuleChainId ruleChainId; - private final String ruleChainName; - private final EntityId componentId; - private final String componentName; - private final ComponentLifecycleEvent eventType; - private final Exception error; - } - } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java index 8d200c4ae3..4436b4737f 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java @@ -16,11 +16,11 @@ package org.thingsboard.server.service.notification.rule.trigger; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; -import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger; import java.util.Set; -public interface RuleEngineMsgNotificationRuleTriggerProcessor extends NotificationRuleTriggerProcessor { +public interface RuleEngineMsgNotificationRuleTriggerProcessor extends NotificationRuleTriggerProcessor { Set getSupportedMsgTypes(); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java index 608f1904c8..5956d2b2dd 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java @@ -50,9 +50,10 @@ import org.thingsboard.server.common.stats.TbApiUsageReportClient; import org.thingsboard.server.dao.alarm.AlarmApiCallResult; import org.thingsboard.server.dao.alarm.AlarmOperationResult; import org.thingsboard.server.dao.alarm.AlarmService; +import org.thingsboard.server.dao.notification.NotificationRuleProcessingService; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService; -import org.thingsboard.server.dao.notification.NotificationRuleProcessingService; +import org.thingsboard.server.dao.notification.trigger.AlarmTrigger; import org.thingsboard.server.service.subscription.TbSubscriptionUtils; import java.util.Collection; @@ -234,7 +235,9 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService return TbSubscriptionUtils.toAlarmUpdateProto(tenantId, entityId, alarm); }); } - notificationRuleProcessingService.process(tenantId, result); + notificationRuleProcessingService.process(tenantId, AlarmTrigger.builder() + .alarmUpdate(result) + .build()); }); } @@ -249,7 +252,9 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService return TbSubscriptionUtils.toAlarmDeletedProto(tenantId, entityId, alarm); }); } - notificationRuleProcessingService.process(tenantId, result); + notificationRuleProcessingService.process(tenantId, AlarmTrigger.builder() + .alarmUpdate(result) + .build()); }); } diff --git a/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java b/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java index 770cb9921c..ed4d43a5fd 100644 --- a/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java @@ -25,8 +25,10 @@ import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.UpdateMessage; -import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionTrigger; import org.thingsboard.server.dao.notification.NotificationRuleProcessingService; +import org.thingsboard.server.queue.util.TbCoreComponent; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -133,7 +135,9 @@ public class DefaultUpdateService implements UpdateService { response.get("updateAvailable").asBoolean() ); if (updateMessage.isUpdateAvailable() && !updateMessage.equals(prevUpdateMessage)) { - notificationRuleProcessingService.process(updateMessage); + notificationRuleProcessingService.process(TenantId.SYS_TENANT_ID, NewPlatformVersionTrigger.builder() + .message(updateMessage) + .build()); } } catch (Exception e) { log.trace(e.getMessage()); diff --git a/application/src/test/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateServiceTest.java index 2729f8ec7a..d650e619a9 100644 --- a/application/src/test/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateServiceTest.java @@ -18,31 +18,27 @@ package org.thingsboard.server.service.apiusage; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.msg.queue.ServiceType; -import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; import org.thingsboard.server.queue.discovery.PartitionService; -import org.thingsboard.server.queue.scheduler.SchedulerComponent; import org.thingsboard.server.service.executors.DbCallbackExecutorService; import java.util.UUID; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.BDDMockito.willReturn; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; @RunWith(MockitoJUnitRunner.class) public class DefaultTbApiUsageStateServiceTest { @@ -68,11 +64,12 @@ public class DefaultTbApiUsageStateServiceTest { TenantId tenantId = TenantId.fromUUID(UUID.fromString("00797a3b-7aeb-4b5b-b57a-c2a810d0f112")); + @Spy + @InjectMocks DefaultTbApiUsageStateService service; @Before public void setUp() { - service = spy(new DefaultTbApiUsageStateService(clusterService, partitionService, tenantService, tsService, apiUsageStateService, tenantProfileCache, mailService, dbExecutor)); } @Test diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java index 3311bb1c1f..f1a76b147a 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java @@ -110,6 +110,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { @Before public void beforeEach() throws Exception { loginTenantAdmin(); + } @Test diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleProcessingService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleProcessingService.java index 54faa040c0..f144db7a62 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleProcessingService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleProcessingService.java @@ -15,30 +15,14 @@ */ package org.thingsboard.server.dao.notification; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.UpdateMessage; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; -import org.thingsboard.server.dao.alarm.AlarmApiCallResult; public interface NotificationRuleProcessingService { + void process(TenantId tenantId, NotificationRuleTrigger trigger); + void process(TenantId tenantId, TbMsg ruleEngineMsg); - // for handling internal component lifecycle events that are not getting to rule chain - void process(ComponentLifecycleMsg componentLifecycleMsg); - - void process(TenantId tenantId, AlarmApiCallResult alarmUpdate); - - void process(TenantId tenantId, RuleChainId ruleChainId, String ruleChainName, - EntityId componentId, String componentName, ComponentLifecycleEvent eventType, Exception error); - - void process(UpdateMessage platformUpdateMessage); - - void process(TenantId tenantId, EntityType entityType, long limit, long currentCount); - } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/AlarmTrigger.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/AlarmTrigger.java new file mode 100644 index 0000000000..309e48a3fc --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/AlarmTrigger.java @@ -0,0 +1,41 @@ +/** + * 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.dao.notification.trigger; + +import lombok.Builder; +import lombok.Data; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.dao.alarm.AlarmApiCallResult; + +@Data +@Builder +public class AlarmTrigger implements NotificationRuleTrigger { + + private final AlarmApiCallResult alarmUpdate; + + @Override + public NotificationRuleTriggerType getType() { + return NotificationRuleTriggerType.ALARM; + } + + @Override + public EntityId getOriginatorEntityId() { + return alarmUpdate.getAlarm().getId(); + } + +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/EntitiesLimitTrigger.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/EntitiesLimitTrigger.java new file mode 100644 index 0000000000..01255d2808 --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/EntitiesLimitTrigger.java @@ -0,0 +1,44 @@ +/** + * 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.dao.notification.trigger; + +import lombok.Builder; +import lombok.Data; +import org.thingsboard.server.common.data.EntityType; +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.NotificationRuleTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; + +@Data +@Builder +public class EntitiesLimitTrigger implements NotificationRuleTrigger { + + private final EntityType entityType; + private final long currentCount; + private final long limit; + + @Override + public NotificationRuleTriggerType getType() { + return NotificationRuleTriggerType.ENTITIES_LIMIT; + } + + @Override + public EntityId getOriginatorEntityId() { + return TenantId.SYS_TENANT_ID; + } + +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/RuleEngineComponentLifecycleEventTrigger.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/RuleEngineComponentLifecycleEventTrigger.java new file mode 100644 index 0000000000..6f096d2b40 --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/RuleEngineComponentLifecycleEventTrigger.java @@ -0,0 +1,47 @@ +/** + * 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.dao.notification.trigger; + +import lombok.Builder; +import lombok.Data; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; + +@Data +@Builder +public class RuleEngineComponentLifecycleEventTrigger implements NotificationRuleTrigger { + + private final RuleChainId ruleChainId; + private final String ruleChainName; + private final EntityId componentId; + private final String componentName; + private final ComponentLifecycleEvent eventType; + private final Exception error; + + @Override + public NotificationRuleTriggerType getType() { + return NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT; + } + + @Override + public EntityId getOriginatorEntityId() { + return componentId; + } + +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/RuleEngineMsgTrigger.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/RuleEngineMsgTrigger.java new file mode 100644 index 0000000000..6e186c90c3 --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/RuleEngineMsgTrigger.java @@ -0,0 +1,42 @@ +/** + * 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.dao.notification.trigger; + +import lombok.Builder; +import lombok.Data; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.msg.TbMsg; + +@Data +@Builder +public class RuleEngineMsgTrigger implements NotificationRuleTrigger { + + private final TbMsg msg; + private final NotificationRuleTriggerType triggerType; + + @Override + public NotificationRuleTriggerType getType() { + return triggerType; + } + + @Override + public EntityId getOriginatorEntityId() { + return msg.getOriginator(); + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntitiesLimitNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntitiesLimitNotificationInfo.java index 0cd5e78cf6..c29620c6c5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntitiesLimitNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntitiesLimitNotificationInfo.java @@ -32,13 +32,18 @@ import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf; public class EntitiesLimitNotificationInfo implements NotificationInfo { private EntityType entityType; - private int threshold; + private long currentCount; + private long limit; + private int percents; @Override public Map getTemplateData() { return mapOf( "entityType", entityType.normalName(), - "threshold", String.valueOf(threshold) + "currentCount", String.valueOf(currentCount), + "limit", String.valueOf(limit), + "percents", String.valueOf(percents) ); } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java index 0382aaccf2..b799d4b81c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java @@ -28,8 +28,6 @@ public class EntitiesLimitNotificationRuleTriggerConfig implements NotificationR @Max(1) private float threshold; // in percents, - // TODO: don't forget to create default notification configs - @Override public NotificationRuleTriggerType getTriggerType() { return NotificationRuleTriggerType.ENTITIES_LIMIT; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionTrigger.java new file mode 100644 index 0000000000..2959c22b8d --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionTrigger.java @@ -0,0 +1,40 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.notification.rule.trigger; + +import lombok.Builder; +import lombok.Data; +import org.thingsboard.server.common.data.UpdateMessage; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; + +@Data +@Builder +public class NewPlatformVersionTrigger implements NotificationRuleTrigger { + + private final UpdateMessage message; + + @Override + public NotificationRuleTriggerType getType() { + return NotificationRuleTriggerType.NEW_PLATFORM_VERSION; + } + + @Override + public EntityId getOriginatorEntityId() { + return TenantId.SYS_TENANT_ID; + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTrigger.java new file mode 100644 index 0000000000..a2ac4c9d47 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTrigger.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.notification.rule.trigger; + +import org.thingsboard.server.common.data.id.EntityId; + +public interface NotificationRuleTrigger { + + NotificationRuleTriggerType getType(); + + EntityId getOriginatorEntityId(); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/DefaultApiLimitService.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/DefaultApiLimitService.java index 24d2e4eb3a..510949e97c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/DefaultApiLimitService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/DefaultApiLimitService.java @@ -26,9 +26,9 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityTypeFilter; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.entity.EntityService; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.usagerecord.ApiLimitService; import org.thingsboard.server.dao.notification.NotificationRuleProcessingService; +import org.thingsboard.server.dao.notification.trigger.EntitiesLimitTrigger; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; @Service @RequiredArgsConstructor @@ -48,7 +48,11 @@ public class DefaultApiLimitService implements ApiLimitService { filter.setEntityType(entityType); long currentCount = entityService.countEntitiesByQuery(tenantId, new CustomerId(EntityId.NULL_UUID), new EntityCountQuery(filter)); if (notificationRuleProcessingService != null) { - notificationRuleProcessingService.process(tenantId, entityType, limit, currentCount); + notificationRuleProcessingService.process(tenantId, EntitiesLimitTrigger.builder() + .entityType(entityType) + .currentCount(currentCount) + .limit(limit) + .build()); } return currentCount < limit; } else { diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java index 3ce142fa63..0102d9c645 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java @@ -47,6 +47,7 @@ public interface MailService { void sendTwoFaVerificationEmail(String email, String verificationCode, int expirationTimeSeconds) throws ThingsboardException; void send(TenantId tenantId, CustomerId customerId, TbEmail tbEmail) throws ThingsboardException; + void send(TenantId tenantId, CustomerId customerId, TbEmail tbEmail, JavaMailSender javaMailSender, long timeout) throws ThingsboardException; void sendApiFeatureStateEmail(ApiFeature apiFeature, ApiUsageStateValue stateValue, String email, ApiUsageStateMailMessage msg) throws ThingsboardException;