Browse Source

Merge remote-tracking branch 'klimov/feature/notification-system' into feature/notification-system

pull/7911/head
Vladyslav_Prykhodko 4 years ago
parent
commit
26618fa3a2
  1. 11
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java
  2. 26
      application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java
  3. 111
      application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java
  4. 16
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java
  5. 23
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java
  6. 12
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java
  7. 18
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java
  8. 29
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntitiesLimitTriggerProcessor.java
  9. 28
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java
  10. 23
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java
  11. 9
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java
  12. 50
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java
  13. 4
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java
  14. 11
      application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java
  15. 8
      application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java
  16. 11
      application/src/test/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateServiceTest.java
  17. 1
      application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java
  18. 22
      common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleProcessingService.java
  19. 41
      common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/AlarmTrigger.java
  20. 44
      common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/EntitiesLimitTrigger.java
  21. 47
      common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/RuleEngineComponentLifecycleEventTrigger.java
  22. 42
      common/dao-api/src/main/java/org/thingsboard/server/dao/notification/trigger/RuleEngineMsgTrigger.java
  23. 9
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntitiesLimitNotificationInfo.java
  24. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java
  25. 40
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionTrigger.java
  26. 26
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTrigger.java
  27. 10
      dao/src/main/java/org/thingsboard/server/dao/usagerecord/DefaultApiLimitService.java
  28. 1
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java

11
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.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.dao.notification.trigger.RuleEngineComponentLifecycleEventTrigger;
public abstract class RuleEngineComponentActor<T extends EntityId, P extends ComponentMsgProcessor<T>> extends ComponentActor<T, P> { public abstract class RuleEngineComponentActor<T extends EntityId, P extends ComponentMsgProcessor<T>> extends ComponentActor<T, P> {
@ -32,8 +33,14 @@ public abstract class RuleEngineComponentActor<T extends EntityId, P extends Com
@Override @Override
protected void logLifecycleEvent(ComponentLifecycleEvent event, Exception e) { protected void logLifecycleEvent(ComponentLifecycleEvent event, Exception e) {
super.logLifecycleEvent(event, e); super.logLifecycleEvent(event, e);
systemContext.getNotificationRuleProcessingService().process(tenantId, getRuleChainId(), getRuleChainName(), systemContext.getNotificationRuleProcessingService().process(tenantId, RuleEngineComponentLifecycleEventTrigger.builder()
id, processor.getComponentName(), event, e); .ruleChainId(getRuleChainId())
.ruleChainName(getRuleChainName())
.componentId(id)
.componentName(processor.getComponentName())
.eventType(event)
.error(e)
.build());
} }
protected abstract RuleChainId getRuleChainId(); protected abstract RuleChainId getRuleChainId();

26
application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java

@ -17,6 +17,7 @@ package org.thingsboard.server.service.apiusage;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -52,6 +53,7 @@ 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;
import org.thingsboard.server.common.msg.tools.SchedulerUtils; import org.thingsboard.server.common.msg.tools.SchedulerUtils;
import org.thingsboard.server.dao.notification.NotificationRuleProcessingService;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.timeseries.TimeseriesService;
@ -86,6 +88,7 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor
public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService<EntityId> implements TbApiUsageStateService { public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService<EntityId> implements TbApiUsageStateService {
public static final String HOURLY = "Hourly"; public static final String HOURLY = "Hourly";
@ -105,6 +108,7 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService
private final ApiUsageStateService apiUsageStateService; private final ApiUsageStateService apiUsageStateService;
private final TbTenantProfileCache tenantProfileCache; private final TbTenantProfileCache tenantProfileCache;
private final MailService mailService; private final MailService mailService;
private final NotificationRuleProcessingService notificationRuleProcessingService;
private final DbCallbackExecutorService dbExecutor; private final DbCallbackExecutorService dbExecutor;
@Lazy @Lazy
@ -126,26 +130,7 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService
private final Lock updateLock = new ReentrantLock(); private final Lock updateLock = new ReentrantLock();
private final ExecutorService mailExecutor; private final ExecutorService mailExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("api-usage-svc-mail"));
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;
}
@PostConstruct @PostConstruct
public void init() { public void init() {
@ -355,6 +340,7 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService
tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK); tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK);
if (state.getEntityType() == EntityType.TENANT && !state.getEntityId().equals(TenantId.SYS_TENANT_ID)) { if (state.getEntityType() == EntityType.TENANT && !state.getEntityId().equals(TenantId.SYS_TENANT_ID)) {
String email = tenantService.findTenantById(state.getTenantId()).getEmail(); String email = tenantService.findTenantById(state.getTenantId()).getEmail();
if (StringUtils.isNotEmpty(email)) { if (StringUtils.isNotEmpty(email)) {
result.forEach((apiFeature, stateValue) -> { result.forEach((apiFeature, stateValue) -> {

111
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.springframework.stereotype.Service;
import org.thingsboard.rule.engine.api.NotificationCenter; import org.thingsboard.rule.engine.api.NotificationCenter;
import org.thingsboard.server.common.data.EntityType; 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.EntityId;
import org.thingsboard.server.common.data.id.NotificationRequestId; import org.thingsboard.server.common.data.id.NotificationRequestId;
import org.thingsboard.server.common.data.id.NotificationRuleId; 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.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationRequest; import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.notification.NotificationRequestConfig; import org.thingsboard.server.common.data.notification.NotificationRequestConfig;
import org.thingsboard.server.common.data.notification.NotificationRequestStatus; import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
import org.thingsboard.server.common.data.notification.info.NotificationInfo; 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.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.NotificationRuleTriggerConfig;
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.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 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.NotificationRequestService;
import org.thingsboard.server.dao.notification.NotificationRuleProcessingService; import org.thingsboard.server.dao.notification.NotificationRuleProcessingService;
import org.thingsboard.server.dao.notification.NotificationRuleService; 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.executors.NotificationExecutorService;
import org.thingsboard.server.service.notification.rule.trigger.NotificationRuleTriggerProcessor; 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 org.thingsboard.server.service.notification.rule.trigger.RuleEngineMsgNotificationRuleTriggerProcessor;
import java.util.Collection; import java.util.Collection;
@ -60,7 +58,7 @@ import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j @Slf4j
@SuppressWarnings("rawtypes") @SuppressWarnings({"rawtypes", "unchecked"})
public class DefaultNotificationRuleProcessingService implements NotificationRuleProcessingService { public class DefaultNotificationRuleProcessingService implements NotificationRuleProcessingService {
private final NotificationRuleService notificationRuleService; private final NotificationRuleService notificationRuleService;
@ -74,80 +72,37 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
private final Map<String, NotificationRuleTriggerType> ruleEngineMsgTypeToTriggerType = new HashMap<>(); private final Map<String, NotificationRuleTriggerType> ruleEngineMsgTypeToTriggerType = new HashMap<>();
@Override @Override
public void process(TenantId tenantId, TbMsg ruleEngineMsg) { public void process(TenantId tenantId, NotificationRuleTrigger trigger) {
String msgType = ruleEngineMsg.getType(); List<NotificationRule> rules = notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, trigger.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<NotificationRule> rules = notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, triggerType);
for (NotificationRule rule : rules) { for (NotificationRule rule : rules) {
notificationExecutor.submit(() -> { notificationExecutor.submit(() -> {
try { try {
processNotificationRule(rule, originatorEntityId, triggerObject); processNotificationRule(rule, trigger);
} catch (Throwable e) { } 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(); NotificationRuleTriggerConfig triggerConfig = rule.getTriggerConfig();
log.debug("Processing notification rule '{}' for trigger type {}", rule.getName(), rule.getTriggerType()); log.debug("Processing notification rule '{}' for trigger type {}", rule.getName(), rule.getTriggerType());
if (matchesClearRule(triggerObject, triggerConfig)) { if (matchesClearRule(trigger, triggerConfig)) {
List<NotificationRequest> notificationRequests = notificationRequestService.findNotificationRequestsByRuleIdAndOriginatorEntityId(rule.getTenantId(), rule.getId(), originatorEntityId); List<NotificationRequest> notificationRequests = notificationRequestService.findNotificationRequestsByRuleIdAndOriginatorEntityId(rule.getTenantId(), rule.getId(), trigger.getOriginatorEntityId());
if (notificationRequests.isEmpty()) { if (notificationRequests.isEmpty()) {
return; return;
} }
@ -156,8 +111,8 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
.filter(NotificationRequest::isSent) .filter(NotificationRequest::isSent)
.flatMap(notificationRequest -> notificationRequest.getTargets().stream()) .flatMap(notificationRequest -> notificationRequest.getTargets().stream())
.distinct().collect(Collectors.toList()); .distinct().collect(Collectors.toList());
NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); NotificationInfo notificationInfo = constructNotificationInfo(trigger, triggerConfig);
submitNotificationRequest(targets, rule, originatorEntityId, notificationInfo, 0); submitNotificationRequest(targets, rule, trigger.getOriginatorEntityId(), notificationInfo, 0);
notificationRequests.forEach(notificationRequest -> { notificationRequests.forEach(notificationRequest -> {
if (notificationRequest.isScheduled()) { if (notificationRequest.isScheduled()) {
@ -167,24 +122,24 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
return; return;
} }
if (matchesFilter(triggerObject, triggerConfig)) { if (matchesFilter(trigger, triggerConfig)) {
NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); NotificationInfo notificationInfo = constructNotificationInfo(trigger, triggerConfig);
rule.getRecipientsConfig().getTargetsTable().forEach((delay, targets) -> { 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) { private boolean matchesFilter(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) {
return triggerProcessors.get(triggerConfig.getTriggerType()).matchesFilter(triggerObject, triggerConfig); return triggerProcessors.get(triggerConfig.getTriggerType()).matchesFilter(trigger, triggerConfig);
} }
private boolean matchesClearRule(Object triggerObject, NotificationRuleTriggerConfig triggerConfig) { private boolean matchesClearRule(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) {
return triggerProcessors.get(triggerConfig.getTriggerType()).matchesClearRule(triggerObject, triggerConfig); return triggerProcessors.get(triggerConfig.getTriggerType()).matchesClearRule(trigger, triggerConfig);
} }
private NotificationInfo constructNotificationInfo(Object triggerObject, NotificationRuleTriggerConfig triggerConfig) { private NotificationInfo constructNotificationInfo(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) {
return triggerProcessors.get(triggerConfig.getTriggerType()).constructNotificationInfo(triggerObject, triggerConfig); return triggerProcessors.get(triggerConfig.getTriggerType()).constructNotificationInfo(trigger, triggerConfig);
} }
private void submitNotificationRequest(List<UUID> targets, NotificationRule rule, private void submitNotificationRequest(List<UUID> targets, NotificationRule rule,

16
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;
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.TbMsg; import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger;
import java.util.Set; import java.util.Set;
@ -37,28 +37,28 @@ import static org.apache.commons.collections.CollectionUtils.isEmpty;
public class AlarmAssignmentTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<AlarmAssignmentNotificationRuleTriggerConfig> { public class AlarmAssignmentTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<AlarmAssignmentNotificationRuleTriggerConfig> {
@Override @Override
public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(RuleEngineMsgTrigger trigger, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) {
Action action = ruleEngineMsg.getType().equals(DataConstants.ALARM_ASSIGN) ? Action.ASSIGNED : Action.UNASSIGNED; Action action = trigger.getMsg().getType().equals(DataConstants.ALARM_ASSIGN) ? Action.ASSIGNED : Action.UNASSIGNED;
if (!triggerConfig.getNotifyOn().contains(action)) { if (!triggerConfig.getNotifyOn().contains(action)) {
return false; 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())) && return (isEmpty(triggerConfig.getAlarmTypes()) || triggerConfig.getAlarmTypes().contains(alarm.getType())) &&
(isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())) && (isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())) &&
(isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarm)); (isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarm));
} }
@Override @Override
public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { public NotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) {
AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class); AlarmInfo alarmInfo = JacksonUtil.fromString(trigger.getMsg().getData(), AlarmInfo.class);
AlarmAssignee assignee = alarmInfo.getAssignee(); AlarmAssignee assignee = alarmInfo.getAssignee();
return AlarmAssignmentNotificationInfo.builder() 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) .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)
.userName(ruleEngineMsg.getMetaData().getValue("userName")) .userName(trigger.getMsg().getMetaData().getValue("userName"))
.alarmId(alarmInfo.getUuidId()) .alarmId(alarmInfo.getUuidId())
.alarmType(alarmInfo.getType()) .alarmType(alarmInfo.getType())
.alarmOriginator(alarmInfo.getOriginator()) .alarmOriginator(alarmInfo.getOriginator())

23
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.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.TbMsg;
import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger;
import java.util.Set; import java.util.Set;
@ -37,33 +38,35 @@ import static org.apache.commons.collections.CollectionUtils.isEmpty;
public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<AlarmCommentNotificationRuleTriggerConfig> { public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<AlarmCommentNotificationRuleTriggerConfig> {
@Override @Override
public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(RuleEngineMsgTrigger trigger, AlarmCommentNotificationRuleTriggerConfig triggerConfig) {
if (ruleEngineMsg.getMetaData().getValue("comment") == null) { TbMsg msg = trigger.getMsg();
if (msg.getMetaData().getValue("comment") == null) {
return false; return false;
} }
if (ruleEngineMsg.getType().equals(DataConstants.COMMENT_UPDATED) && !triggerConfig.isNotifyOnCommentUpdate()) { if (msg.getType().equals(DataConstants.COMMENT_UPDATED) && !triggerConfig.isNotifyOnCommentUpdate()) {
return false; return false;
} }
if (triggerConfig.isOnlyUserComments()) { 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) { if (comment.getType() == AlarmCommentType.SYSTEM) {
return false; 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())) && return (isEmpty(triggerConfig.getAlarmTypes()) || triggerConfig.getAlarmTypes().contains(alarm.getType())) &&
(isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())) && (isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())) &&
(isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarm)); (isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarm));
} }
@Override @Override
public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { public NotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger, AlarmCommentNotificationRuleTriggerConfig triggerConfig) {
AlarmComment comment = JacksonUtil.fromString(ruleEngineMsg.getMetaData().getValue("comment"), AlarmComment.class); TbMsg msg = trigger.getMsg();
AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class); AlarmComment comment = JacksonUtil.fromString(msg.getMetaData().getValue("comment"), AlarmComment.class);
AlarmInfo alarmInfo = JacksonUtil.fromString(msg.getData(), AlarmInfo.class);
return AlarmCommentNotificationInfo.builder() return AlarmCommentNotificationInfo.builder()
.comment(comment.getComment().get("text").asText()) .comment(comment.getComment().get("text").asText())
.action(ruleEngineMsg.getType().equals(DataConstants.COMMENT_CREATED) ? "added" : "updated") .action(msg.getType().equals(DataConstants.COMMENT_CREATED) ? "added" : "updated")
.userName(ruleEngineMsg.getMetaData().getValue("userName")) .userName(msg.getMetaData().getValue("userName"))
.alarmId(alarmInfo.getUuidId()) .alarmId(alarmInfo.getUuidId())
.alarmType(alarmInfo.getType()) .alarmType(alarmInfo.getType())
.alarmOriginator(alarmInfo.getOriginator()) .alarmOriginator(alarmInfo.getOriginator())

12
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.AlarmNotificationRuleTriggerConfig.ClearRule;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.dao.alarm.AlarmApiCallResult; 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.isEmpty;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty; import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
@Service @Service
public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor<AlarmApiCallResult, AlarmNotificationRuleTriggerConfig> { public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor<AlarmTrigger, AlarmNotificationRuleTriggerConfig> {
@Override @Override
public boolean matchesFilter(AlarmApiCallResult alarmUpdate, AlarmNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(AlarmTrigger trigger, AlarmNotificationRuleTriggerConfig triggerConfig) {
AlarmApiCallResult alarmUpdate = trigger.getAlarmUpdate();
Alarm alarm = alarmUpdate.getAlarm(); Alarm alarm = alarmUpdate.getAlarm();
if (!typeMatches(alarm, triggerConfig)) { if (!typeMatches(alarm, triggerConfig)) {
return false; return false;
@ -64,7 +66,8 @@ public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor<A
} }
@Override @Override
public boolean matchesClearRule(AlarmApiCallResult alarmUpdate, AlarmNotificationRuleTriggerConfig triggerConfig) { public boolean matchesClearRule(AlarmTrigger trigger, AlarmNotificationRuleTriggerConfig triggerConfig) {
AlarmApiCallResult alarmUpdate = trigger.getAlarmUpdate();
Alarm alarm = alarmUpdate.getAlarm(); Alarm alarm = alarmUpdate.getAlarm();
if (!typeMatches(alarm, triggerConfig)) { if (!typeMatches(alarm, triggerConfig)) {
return false; return false;
@ -90,7 +93,8 @@ public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor<A
} }
@Override @Override
public NotificationInfo constructNotificationInfo(AlarmApiCallResult alarmUpdate, AlarmNotificationRuleTriggerConfig triggerConfig) { public NotificationInfo constructNotificationInfo(AlarmTrigger trigger, AlarmNotificationRuleTriggerConfig triggerConfig) {
AlarmApiCallResult alarmUpdate = trigger.getAlarmUpdate();
AlarmInfo alarmInfo = alarmUpdate.getAlarm(); AlarmInfo alarmInfo = alarmUpdate.getAlarm();
return AlarmNotificationInfo.builder() return AlarmNotificationInfo.builder()
.alarmId(alarmInfo.getUuidId()) .alarmId(alarmInfo.getUuidId())

18
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java

@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.DeviceInactivityNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.DeviceInactivityNotificationRuleTriggerConfig;
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.TbMsg;
import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import java.util.Set; import java.util.Set;
@ -38,8 +39,8 @@ public class DeviceInactivityTriggerProcessor implements RuleEngineMsgNotificati
private final TbDeviceProfileCache deviceProfileCache; private final TbDeviceProfileCache deviceProfileCache;
@Override @Override
public boolean matchesFilter(TbMsg ruleEngineMsg, DeviceInactivityNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(RuleEngineMsgTrigger trigger, DeviceInactivityNotificationRuleTriggerConfig triggerConfig) {
DeviceId deviceId = (DeviceId) ruleEngineMsg.getOriginator(); DeviceId deviceId = (DeviceId) trigger.getMsg().getOriginator();
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())) {
@ -51,13 +52,14 @@ public class DeviceInactivityTriggerProcessor implements RuleEngineMsgNotificati
} }
@Override @Override
public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, DeviceInactivityNotificationRuleTriggerConfig triggerConfig) { public NotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger, DeviceInactivityNotificationRuleTriggerConfig triggerConfig) {
TbMsg msg = trigger.getMsg();
return DeviceInactivityNotificationInfo.builder() return DeviceInactivityNotificationInfo.builder()
.deviceId(ruleEngineMsg.getOriginator().getId()) .deviceId(msg.getOriginator().getId())
.deviceName(ruleEngineMsg.getMetaData().getValue("deviceName")) .deviceName(msg.getMetaData().getValue("deviceName"))
.deviceType(ruleEngineMsg.getMetaData().getValue("deviceType")) .deviceType(msg.getMetaData().getValue("deviceType"))
.deviceLabel(ruleEngineMsg.getMetaData().getValue("deviceLabel")) .deviceLabel(msg.getMetaData().getValue("deviceLabel"))
.deviceCustomerId(ruleEngineMsg.getCustomerId()) .deviceCustomerId(msg.getCustomerId())
.build(); .build();
} }

29
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntitiesLimitTriggerProcessor.java

@ -15,34 +15,33 @@
*/ */
package org.thingsboard.server.service.notification.rule.trigger; package org.thingsboard.server.service.notification.rule.trigger;
import lombok.Builder;
import lombok.Data;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.notification.info.EntitiesLimitNotificationInfo; import org.thingsboard.server.common.data.notification.info.EntitiesLimitNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimitNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimitNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.service.notification.rule.trigger.EntitiesLimitTriggerProcessor.EntitiesLimitTriggerObject; import org.thingsboard.server.dao.notification.trigger.EntitiesLimitTrigger;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty; import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
@Service @Service
public class EntitiesLimitTriggerProcessor implements NotificationRuleTriggerProcessor<EntitiesLimitTriggerObject, EntitiesLimitNotificationRuleTriggerConfig> { public class EntitiesLimitTriggerProcessor implements NotificationRuleTriggerProcessor<EntitiesLimitTrigger, EntitiesLimitNotificationRuleTriggerConfig> {
@Override @Override
public boolean matchesFilter(EntitiesLimitTriggerObject triggerObject, EntitiesLimitNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(EntitiesLimitTrigger trigger, EntitiesLimitNotificationRuleTriggerConfig triggerConfig) {
if (isNotEmpty(triggerConfig.getEntityTypes()) && !triggerConfig.getEntityTypes().contains(triggerObject.getEntityType())) { if (isNotEmpty(triggerConfig.getEntityTypes()) && !triggerConfig.getEntityTypes().contains(trigger.getEntityType())) {
return false; 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 @Override
public NotificationInfo constructNotificationInfo(EntitiesLimitTriggerObject triggerObject, EntitiesLimitNotificationRuleTriggerConfig triggerConfig) { public NotificationInfo constructNotificationInfo(EntitiesLimitTrigger trigger, EntitiesLimitNotificationRuleTriggerConfig triggerConfig) {
return EntitiesLimitNotificationInfo.builder() return EntitiesLimitNotificationInfo.builder()
.entityType(triggerObject.getEntityType()) .entityType(trigger.getEntityType())
.threshold((int) (triggerConfig.getThreshold() * 100)) .currentCount(trigger.getCurrentCount())
.limit(trigger.getLimit())
.percents((int) (((float)trigger.getCurrentCount() / trigger.getLimit()) * 100))
.build(); .build();
} }
@ -51,12 +50,4 @@ public class EntitiesLimitTriggerProcessor implements NotificationRuleTriggerPro
return NotificationRuleTriggerType.ENTITIES_LIMIT; return NotificationRuleTriggerType.ENTITIES_LIMIT;
} }
@Data
@Builder
public static class EntitiesLimitTriggerObject {
private final EntityType entityType;
private final long limit;
private final long currentCount;
}
} }

28
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.DataConstants;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.notification.info.EntityActionNotificationInfo; 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.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig; 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.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -34,8 +34,8 @@ import java.util.UUID;
public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<EntityActionNotificationRuleTriggerConfig> { public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<EntityActionNotificationRuleTriggerConfig> {
@Override @Override
public boolean matchesFilter(TbMsg ruleEngineMsg, EntityActionNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(RuleEngineMsgTrigger trigger, EntityActionNotificationRuleTriggerConfig triggerConfig) {
String msgType = ruleEngineMsg.getType(); String msgType = trigger.getMsg().getType();
if (msgType.equals(DataConstants.ENTITY_CREATED)) { if (msgType.equals(DataConstants.ENTITY_CREATED)) {
if (!triggerConfig.isCreated()) { if (!triggerConfig.isCreated()) {
return false; return false;
@ -51,28 +51,28 @@ public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRu
} else { } else {
return false; return false;
} }
return triggerConfig.getEntityType() == null || getEntityType(ruleEngineMsg) == triggerConfig.getEntityType(); return triggerConfig.getEntityType() == null || getEntityType(trigger.getMsg()) == triggerConfig.getEntityType();
} }
@Override @Override
public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, EntityActionNotificationRuleTriggerConfig triggerConfig) { public NotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger, EntityActionNotificationRuleTriggerConfig triggerConfig) {
EntityId entityId = ruleEngineMsg.getOriginator(); TbMsg msg = trigger.getMsg();
String msgType = ruleEngineMsg.getType(); String msgType = msg.getType();
ActionType actionType = msgType.equals(DataConstants.ENTITY_CREATED) ? ActionType.ADDED : ActionType actionType = msgType.equals(DataConstants.ENTITY_CREATED) ? ActionType.ADDED :
msgType.equals(DataConstants.ENTITY_UPDATED) ? ActionType.UPDATED : msgType.equals(DataConstants.ENTITY_UPDATED) ? ActionType.UPDATED :
msgType.equals(DataConstants.ENTITY_DELETED) ? ActionType.DELETED : null; msgType.equals(DataConstants.ENTITY_DELETED) ? ActionType.DELETED : null;
return EntityActionNotificationInfo.builder() return EntityActionNotificationInfo.builder()
.entityId(actionType != ActionType.DELETED ? entityId : null) .entityId(actionType != ActionType.DELETED ? msg.getOriginator() : null)
.entityName(ruleEngineMsg.getMetaData().getValue("entityName")) .entityName(msg.getMetaData().getValue("entityName"))
.actionType(actionType) .actionType(actionType)
.originatorUserId(UUID.fromString(ruleEngineMsg.getMetaData().getValue("userId"))) .originatorUserId(UUID.fromString(msg.getMetaData().getValue("userId")))
.originatorUserName(ruleEngineMsg.getMetaData().getValue("userName")) .originatorUserName(msg.getMetaData().getValue("userName"))
.entityCustomerId(ruleEngineMsg.getCustomerId()) .entityCustomerId(msg.getCustomerId())
.build(); .build();
} }
private static EntityType getEntityType(TbMsg ruleEngineMsg) { private static EntityType getEntityType(TbMsg msg) {
return Optional.ofNullable(ruleEngineMsg.getMetaData().getValue("entityType")) return Optional.ofNullable(msg.getMetaData().getValue("entityType"))
.map(EntityType::valueOf).orElse(null); .map(EntityType::valueOf).orElse(null);
} }

23
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; package org.thingsboard.server.service.notification.rule.trigger;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; 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.NewPlatformVersionNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo; 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.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.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.queue.discovery.PartitionService;
@Service @Service
public class NewPlatformVersionTriggerProcessor implements NotificationRuleTriggerProcessor<UpdateMessage, NewPlatformVersionNotificationRuleTriggerConfig> { @RequiredArgsConstructor
public class NewPlatformVersionTriggerProcessor implements NotificationRuleTriggerProcessor<NewPlatformVersionTrigger, NewPlatformVersionNotificationRuleTriggerConfig> {
private final PartitionService partitionService;
@Override @Override
public boolean matchesFilter(UpdateMessage triggerObject, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(NewPlatformVersionTrigger trigger, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) {
return triggerObject.isUpdateAvailable(); // 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 @Override
public NotificationInfo constructNotificationInfo(UpdateMessage updateMessage, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) { public NotificationInfo constructNotificationInfo(NewPlatformVersionTrigger trigger, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) {
return NewPlatformVersionNotificationInfo.builder() return NewPlatformVersionNotificationInfo.builder()
.message(updateMessage.getMessage()) .message(trigger.getMessage().getMessage())
.build(); .build();
} }

9
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; package org.thingsboard.server.service.notification.rule.trigger;
import org.thingsboard.server.common.data.notification.info.NotificationInfo; 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.NotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
public interface NotificationRuleTriggerProcessor<T, C extends NotificationRuleTriggerConfig> { public interface NotificationRuleTriggerProcessor<T extends NotificationRuleTrigger, C extends NotificationRuleTriggerConfig> {
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; return false;
} }
NotificationInfo constructNotificationInfo(T triggerObject, C triggerConfig); NotificationInfo constructNotificationInfo(T trigger, C triggerConfig);
NotificationRuleTriggerType getTriggerType(); NotificationRuleTriggerType getTriggerType();

50
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; 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.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.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.NotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleEngineComponentLifecycleEventNotificationInfo; 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.NotificationRuleTriggerType;
import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 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.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.Set; import java.util.Set;
@Service @Service
public class RuleEngineComponentLifecycleEventTriggerProcessor implements NotificationRuleTriggerProcessor<RuleEngineComponentLifecycleEventTriggerObject, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig> { public class RuleEngineComponentLifecycleEventTriggerProcessor implements NotificationRuleTriggerProcessor<RuleEngineComponentLifecycleEventTrigger, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig> {
@Override @Override
public boolean matchesFilter(RuleEngineComponentLifecycleEventTriggerObject triggerObject, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(RuleEngineComponentLifecycleEventTrigger trigger, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) {
if (CollectionUtils.isNotEmpty(triggerConfig.getRuleChains())) { if (CollectionUtils.isNotEmpty(triggerConfig.getRuleChains())) {
if (!triggerConfig.getRuleChains().contains(triggerObject.getRuleChainId().getId())) { if (!triggerConfig.getRuleChains().contains(trigger.getRuleChainId().getId())) {
return false; return false;
} }
} }
EntityType componentType = triggerObject.getComponentId().getEntityType(); EntityType componentType = trigger.getComponentId().getEntityType();
Set<ComponentLifecycleEvent> trackedEvents; Set<ComponentLifecycleEvent> trackedEvents;
boolean onlyFailures; boolean onlyFailures;
if (componentType == EntityType.RULE_CHAIN) { if (componentType == EntityType.RULE_CHAIN) {
@ -63,27 +58,27 @@ public class RuleEngineComponentLifecycleEventTriggerProcessor implements Notifi
trackedEvents = Set.of(ComponentLifecycleEvent.STARTED, ComponentLifecycleEvent.UPDATED, ComponentLifecycleEvent.STOPPED); trackedEvents = Set.of(ComponentLifecycleEvent.STARTED, ComponentLifecycleEvent.UPDATED, ComponentLifecycleEvent.STOPPED);
} }
if (!trackedEvents.contains(triggerObject.getEventType())) { if (!trackedEvents.contains(trigger.getEventType())) {
return false; return false;
} }
if (onlyFailures) { if (onlyFailures) {
return triggerObject.getError() != null; return trigger.getError() != null;
} }
return true; return true;
} }
@Override @Override
public NotificationInfo constructNotificationInfo(RuleEngineComponentLifecycleEventTriggerObject triggerObject, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) { public NotificationInfo constructNotificationInfo(RuleEngineComponentLifecycleEventTrigger trigger, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) {
return RuleEngineComponentLifecycleEventNotificationInfo.builder() return RuleEngineComponentLifecycleEventNotificationInfo.builder()
.ruleChainId(triggerObject.getRuleChainId()) .ruleChainId(trigger.getRuleChainId())
.ruleChainName(triggerObject.getRuleChainName()) .ruleChainName(trigger.getRuleChainName())
.componentId(triggerObject.getComponentId()) .componentId(trigger.getComponentId())
.componentName(triggerObject.getComponentName()) .componentName(trigger.getComponentName())
.action(triggerObject.getEventType() == ComponentLifecycleEvent.STARTED ? "start" : .action(trigger.getEventType() == ComponentLifecycleEvent.STARTED ? "start" :
triggerObject.getEventType() == ComponentLifecycleEvent.UPDATED ? "update" : trigger.getEventType() == ComponentLifecycleEvent.UPDATED ? "update" :
triggerObject.getEventType() == ComponentLifecycleEvent.STOPPED ? "stop" : null) trigger.getEventType() == ComponentLifecycleEvent.STOPPED ? "stop" : null)
.eventType(triggerObject.getEventType()) .eventType(trigger.getEventType())
.error(getErrorMsg(triggerObject.getError())) .error(getErrorMsg(trigger.getError()))
.build(); .build();
} }
@ -100,15 +95,4 @@ public class RuleEngineComponentLifecycleEventTriggerProcessor implements Notifi
return NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT; 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;
}
} }

4
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; package org.thingsboard.server.service.notification.rule.trigger;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; 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; import java.util.Set;
public interface RuleEngineMsgNotificationRuleTriggerProcessor<C extends NotificationRuleTriggerConfig> extends NotificationRuleTriggerProcessor<TbMsg, C> { public interface RuleEngineMsgNotificationRuleTriggerProcessor<C extends NotificationRuleTriggerConfig> extends NotificationRuleTriggerProcessor<RuleEngineMsgTrigger, C> {
Set<String> getSupportedMsgTypes(); Set<String> getSupportedMsgTypes();

11
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.AlarmApiCallResult;
import org.thingsboard.server.dao.alarm.AlarmOperationResult; import org.thingsboard.server.dao.alarm.AlarmOperationResult;
import org.thingsboard.server.dao.alarm.AlarmService; 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.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService; 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 org.thingsboard.server.service.subscription.TbSubscriptionUtils;
import java.util.Collection; import java.util.Collection;
@ -234,7 +235,9 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService
return TbSubscriptionUtils.toAlarmUpdateProto(tenantId, entityId, alarm); 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); return TbSubscriptionUtils.toAlarmDeletedProto(tenantId, entityId, alarm);
}); });
} }
notificationRuleProcessingService.process(tenantId, result); notificationRuleProcessingService.process(tenantId, AlarmTrigger.builder()
.alarmUpdate(result)
.build());
}); });
} }

8
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.springframework.web.client.RestTemplate;
import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.UpdateMessage; 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.dao.notification.NotificationRuleProcessingService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
@ -133,7 +135,9 @@ public class DefaultUpdateService implements UpdateService {
response.get("updateAvailable").asBoolean() response.get("updateAvailable").asBoolean()
); );
if (updateMessage.isUpdateAvailable() && !updateMessage.equals(prevUpdateMessage)) { if (updateMessage.isUpdateAvailable() && !updateMessage.equals(prevUpdateMessage)) {
notificationRuleProcessingService.process(updateMessage); notificationRuleProcessingService.process(TenantId.SYS_TENANT_ID, NewPlatformVersionTrigger.builder()
.message(updateMessage)
.build());
} }
} catch (Exception e) { } catch (Exception e) {
log.trace(e.getMessage()); log.trace(e.getMessage());

11
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.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.ApiUsageState;
import org.thingsboard.server.common.data.id.TenantId; 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.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantService; 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.usagerecord.ApiUsageStateService; import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.scheduler.SchedulerComponent;
import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import java.util.UUID; 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.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class DefaultTbApiUsageStateServiceTest { public class DefaultTbApiUsageStateServiceTest {
@ -68,11 +64,12 @@ public class DefaultTbApiUsageStateServiceTest {
TenantId tenantId = TenantId.fromUUID(UUID.fromString("00797a3b-7aeb-4b5b-b57a-c2a810d0f112")); TenantId tenantId = TenantId.fromUUID(UUID.fromString("00797a3b-7aeb-4b5b-b57a-c2a810d0f112"));
@Spy
@InjectMocks
DefaultTbApiUsageStateService service; DefaultTbApiUsageStateService service;
@Before @Before
public void setUp() { public void setUp() {
service = spy(new DefaultTbApiUsageStateService(clusterService, partitionService, tenantService, tsService, apiUsageStateService, tenantProfileCache, mailService, dbExecutor));
} }
@Test @Test

1
application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java

@ -110,6 +110,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
@Before @Before
public void beforeEach() throws Exception { public void beforeEach() throws Exception {
loginTenantAdmin(); loginTenantAdmin();
} }
@Test @Test

22
common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleProcessingService.java

@ -15,30 +15,14 @@
*/ */
package org.thingsboard.server.dao.notification; 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.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.TbMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.dao.alarm.AlarmApiCallResult;
public interface NotificationRuleProcessingService { public interface NotificationRuleProcessingService {
void process(TenantId tenantId, TbMsg ruleEngineMsg); void process(TenantId tenantId, NotificationRuleTrigger trigger);
// 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, void process(TenantId tenantId, TbMsg ruleEngineMsg);
EntityId componentId, String componentName, ComponentLifecycleEvent eventType, Exception error);
void process(UpdateMessage platformUpdateMessage);
void process(TenantId tenantId, EntityType entityType, long limit, long currentCount);
} }

41
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();
}
}

44
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;
}
}

47
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;
}
}

42
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();
}
}

9
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 { public class EntitiesLimitNotificationInfo implements NotificationInfo {
private EntityType entityType; private EntityType entityType;
private int threshold; private long currentCount;
private long limit;
private int percents;
@Override @Override
public Map<String, String> getTemplateData() { public Map<String, String> getTemplateData() {
return mapOf( return mapOf(
"entityType", entityType.normalName(), "entityType", entityType.normalName(),
"threshold", String.valueOf(threshold) "currentCount", String.valueOf(currentCount),
"limit", String.valueOf(limit),
"percents", String.valueOf(percents)
); );
} }
} }

2
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) @Max(1)
private float threshold; // in percents, private float threshold; // in percents,
// TODO: don't forget to create default notification configs
@Override @Override
public NotificationRuleTriggerType getTriggerType() { public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ENTITIES_LIMIT; return NotificationRuleTriggerType.ENTITIES_LIMIT;

40
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;
}
}

26
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();
}

10
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.query.EntityTypeFilter;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.entity.EntityService; 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.NotificationRuleProcessingService;
import org.thingsboard.server.dao.notification.trigger.EntitiesLimitTrigger;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@ -48,7 +48,11 @@ public class DefaultApiLimitService implements ApiLimitService {
filter.setEntityType(entityType); filter.setEntityType(entityType);
long currentCount = entityService.countEntitiesByQuery(tenantId, new CustomerId(EntityId.NULL_UUID), new EntityCountQuery(filter)); long currentCount = entityService.countEntitiesByQuery(tenantId, new CustomerId(EntityId.NULL_UUID), new EntityCountQuery(filter));
if (notificationRuleProcessingService != null) { if (notificationRuleProcessingService != null) {
notificationRuleProcessingService.process(tenantId, entityType, limit, currentCount); notificationRuleProcessingService.process(tenantId, EntitiesLimitTrigger.builder()
.entityType(entityType)
.currentCount(currentCount)
.limit(limit)
.build());
} }
return currentCount < limit; return currentCount < limit;
} else { } else {

1
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 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) throws ThingsboardException;
void send(TenantId tenantId, CustomerId customerId, TbEmail tbEmail, JavaMailSender javaMailSender, long timeout) 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; void sendApiFeatureStateEmail(ApiFeature apiFeature, ApiUsageStateValue stateValue, String email, ApiUsageStateMailMessage msg) throws ThingsboardException;

Loading…
Cancel
Save