Browse Source

New notification rule triggers: alarm comment and Rule Engine component lifecycle event; refactoring

pull/8046/head
ViacheslavKlimov 3 years ago
parent
commit
7d9fff4e44
  1. 4
      application/src/main/data/upgrade/3.4.3/schema_update.sql
  2. 5
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  3. 5
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java
  4. 2
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
  5. 5
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActor.java
  6. 6
      application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java
  7. 10
      application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java
  8. 6
      application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java
  9. 6
      application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java
  10. 18
      application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java
  11. 28
      application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java
  12. 38
      application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java
  13. 5
      application/src/main/java/org/thingsboard/server/service/notification/rule/NotificationRuleProcessingService.java
  14. 52
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java
  15. 24
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java
  16. 2
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java
  17. 2
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java
  18. 97
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java
  19. 10
      application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java
  20. 2
      common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
  21. 32
      common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java
  22. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java
  23. 45
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java
  24. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java
  25. 54
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java
  26. 28
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java
  27. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java
  28. 6
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java
  29. 41
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.java
  30. 4
      dao/src/main/resources/sql/schema-entities.sql

4
application/src/main/data/upgrade/3.4.3/schema_update.sql

@ -41,7 +41,7 @@ CREATE TABLE IF NOT EXISTS notification_template (
created_time BIGINT NOT NULL,
tenant_id UUID NULL CONSTRAINT fk_notification_template_tenant_id REFERENCES tenant(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
notification_type VARCHAR(32) NOT NULL,
notification_type VARCHAR(50) NOT NULL,
configuration VARCHAR(10000) NOT NULL,
CONSTRAINT uq_notification_template_name UNIQUE (tenant_id, name)
);
@ -84,7 +84,7 @@ CREATE TABLE IF NOT EXISTS notification (
created_time BIGINT NOT NULL,
request_id UUID NULL CONSTRAINT fk_notification_request_id REFERENCES notification_request(id) ON DELETE CASCADE,
recipient_id UUID NOT NULL CONSTRAINT fk_notification_recipient_id REFERENCES tb_user(id) ON DELETE CASCADE,
type VARCHAR(32) NOT NULL,
type VARCHAR(50) NOT NULL,
subject VARCHAR(255),
text VARCHAR(1000) NOT NULL,
additional_config VARCHAR(1000),

5
application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java

@ -95,6 +95,7 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService;
import org.thingsboard.server.service.executors.NotificationExecutorService;
import org.thingsboard.server.service.executors.SharedEventLoopGroupService;
import org.thingsboard.server.service.mail.MailExecutorService;
import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService;
import org.thingsboard.server.service.profile.TbAssetProfileCache;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;
@ -334,6 +335,10 @@ public class ActorSystemContext {
@Getter
private NotificationCenter notificationCenter;
@Autowired
@Getter
private NotificationRuleProcessingService notificationRuleProcessingService;
@Autowired
@Getter
private SlackService slackService;

5
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java

@ -101,6 +101,11 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
}
}
@Override
protected RuleChainId getRuleChainId() {
return ruleChain.getId();
}
@Override
protected long getErrorPersistFrequency() {
return systemContext.getRuleChainErrorPersistFrequency();

2
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java

@ -94,7 +94,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
@Override
public String getComponentName() {
return null;
return ruleChainName;
}
@Override

5
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActor.java

@ -133,6 +133,11 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa
}
}
@Override
protected RuleChainId getRuleChainId() {
return ruleChainId;
}
@Override
protected long getErrorPersistFrequency() {
return systemContext.getRuleNodeErrorPersistFrequency();

6
application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java

@ -17,13 +17,13 @@ package org.thingsboard.server.actors.service;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.TbActor;
import org.thingsboard.server.actors.TbActorCtx;
import org.thingsboard.server.actors.TbActorException;
import org.thingsboard.server.actors.TbRuleNodeUpdateException;
import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
import org.thingsboard.server.actors.stats.StatsPersistMsg;
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.msg.plugin.ComponentLifecycleMsg;
@ -183,7 +183,11 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
private void logLifecycleEvent(ComponentLifecycleEvent event, Exception e) {
systemContext.persistLifecycleEvent(tenantId, id, event, e);
systemContext.getNotificationRuleProcessingService().process(tenantId, getRuleChainId(), id, processor.getComponentName(), event, e);
}
protected abstract RuleChainId getRuleChainId();
protected abstract long getErrorPersistFrequency();
}

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

@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.CustomerId;
@ -89,6 +90,12 @@ public class EntityActionService {
case ALARM_DELETE:
msgType = DataConstants.ALARM_DELETE;
break;
case ADDED_COMMENT:
msgType = DataConstants.COMMENT_CREATED;
break;
case UPDATED_COMMENT:
msgType = DataConstants.COMMENT_UPDATED;
break;
case ASSIGNED_FROM_TENANT:
msgType = DataConstants.ENTITY_ASSIGNED_FROM_TENANT;
break;
@ -163,6 +170,9 @@ public class EntityActionService {
String strEdgeName = extractParameter(String.class, 2, additionalInfo);
metaData.putValue("unassignedEdgeId", strEdgeId);
metaData.putValue("unassignedEdgeName", strEdgeName);
} else if (actionType == ActionType.ADDED_COMMENT || actionType == ActionType.UPDATED_COMMENT) {
AlarmComment comment = extractParameter(AlarmComment.class, 0, additionalInfo);
metaData.putValue("comment", json.writeValueAsString(comment));
}
ObjectNode entityNode;
if (entity != null) {

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

@ -21,6 +21,7 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
@ -34,7 +35,6 @@ import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.alarm.AlarmCommentService;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.edge.EdgeService;
@ -63,11 +63,9 @@ public abstract class AbstractTbEntityService {
protected EdgeService edgeService;
@Autowired
protected AlarmService alarmService;
@Autowired
@Autowired @Lazy
protected AlarmSubscriptionService alarmSubscriptionService;
@Autowired
protected AlarmCommentService alarmCommentService;
@Autowired
protected CustomerService customerService;
@Autowired
protected TbClusterService tbClusterService;

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

@ -16,6 +16,7 @@
package org.thingsboard.server.service.entitiy.alarm;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
@ -24,11 +25,16 @@ import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.dao.alarm.AlarmCommentService;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
@Service
@AllArgsConstructor
public class DefaultTbAlarmCommentService extends AbstractTbEntityService implements TbAlarmCommentService{
@Autowired
private AlarmCommentService alarmCommentService;
@Override
public AlarmComment saveAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) throws ThingsboardException {
ActionType actionType = alarmComment.getId() == null ? ActionType.ADDED_COMMENT : ActionType.UPDATED_COMMENT;

18
application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java

@ -19,6 +19,8 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntityType;
@ -37,8 +39,12 @@ import java.util.List;
@Service
@AllArgsConstructor
@Slf4j
public class DefaultTbAlarmService extends AbstractTbEntityService implements TbAlarmService {
@Autowired
protected TbAlarmCommentService alarmCommentService;
@Override
public Alarm save(Alarm alarm, User user) throws ThingsboardException {
ActionType actionType = alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
@ -65,7 +71,11 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
(user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()))
.put("userId", user.getId().toString()))
.build();
alarmCommentService.createOrUpdateAlarmComment(alarm.getTenantId(), alarmComment);
try {
alarmCommentService.saveAlarmComment(alarm, alarmComment, user);
} catch (ThingsboardException e) {
log.error("Failed to save alarm comment", e);
}
alarm.setAckTs(ackTs);
alarm.setStatus(alarm.getStatus().isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK);
notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_ACK, user);
@ -85,7 +95,11 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
(user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()))
.put("userId", user.getId().toString()))
.build();
alarmCommentService.createOrUpdateAlarmComment(alarm.getTenantId(), alarmComment);
try {
alarmCommentService.saveAlarmComment(alarm, alarmComment, user);
} catch (ThingsboardException e) {
log.error("Failed to save alarm comment", e);
}
alarm.setClearTs(clearTs);
alarm.setStatus(alarm.getStatus().isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK);
notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_CLEAR, user);

28
application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java

@ -42,7 +42,6 @@ import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.common.data.notification.targets.NotificationRecipient;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversation;
import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
@ -118,8 +117,10 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
throw new IllegalArgumentException("Slack must be configured in the settings");
}
}
if (targets.stream().noneMatch(target -> target.getConfiguration().getType().getSupportedDeliveryMethods().contains(deliveryMethod))) {
throw new IllegalArgumentException("Target for " + deliveryMethod.getName() + " delivery method is missing");
if (notificationRequest.getRuleId() == null) {
if (targets.stream().noneMatch(target -> target.getConfiguration().getType().getSupportedDeliveryMethods().contains(deliveryMethod))) {
throw new IllegalArgumentException("Target for " + deliveryMethod.getName() + " delivery method is missing");
}
}
});
@ -204,15 +205,17 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
log.debug("[{}] Processing notification request for {} target ({}) for delivery methods {}", ctx.getRequest().getId(), target.getConfiguration().getType(), target.getId(), deliveryMethods);
List<ListenableFuture<Void>> results = new ArrayList<>();
for (NotificationRecipient recipient : recipients) {
for (NotificationDeliveryMethod deliveryMethod : deliveryMethods) {
ListenableFuture<Void> resultFuture = processForRecipient(deliveryMethod, recipient, ctx);
DonAsynchron.withCallback(resultFuture, result -> {
ctx.getStats().reportSent(deliveryMethod, recipient);
}, error -> {
ctx.getStats().reportError(deliveryMethod, error, recipient);
});
results.add(resultFuture);
if (!deliveryMethods.isEmpty()) {
for (NotificationRecipient recipient : recipients) {
for (NotificationDeliveryMethod deliveryMethod : deliveryMethods) {
ListenableFuture<Void> resultFuture = processForRecipient(deliveryMethod, recipient, ctx);
DonAsynchron.withCallback(resultFuture, result -> {
ctx.getStats().reportSent(deliveryMethod, recipient);
}, error -> {
ctx.getStats().reportError(deliveryMethod, error, recipient);
});
results.add(resultFuture);
}
}
}
return results;
@ -333,6 +336,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
// marking related notifications as unread: FIXME: causes each subscription to fetch notifications on each request update
notificationService.updateNotificationsStatusByRequestId(tenantId, notificationRequest.getId(), NotificationStatus.SENT);
// TODO: no need to update request with other than PLATFORM_USERS target type
onNotificationRequestUpdate(tenantId, NotificationRequestUpdate.builder()
.notificationRequestId(notificationRequest.getId())
.notificationInfo(notificationRequest.getInfo())

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

@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.alarm.Alarm;
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;
@ -45,7 +46,9 @@ import org.thingsboard.server.dao.notification.NotificationRequestService;
import org.thingsboard.server.dao.notification.NotificationRuleService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.executors.NotificationExecutorService;
import org.thingsboard.server.service.notification.rule.trigger.AlarmTriggerProcessor.AlarmTriggerObject;
import org.thingsboard.server.service.notification.rule.trigger.NotificationRuleTriggerProcessor;
import org.thingsboard.server.service.notification.rule.trigger.RuleEngineComponentLifecycleEventTriggerProcessor.RuleEngineComponentLifecycleEventTriggerObject;
import java.util.Collection;
import java.util.List;
@ -71,7 +74,9 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
DataConstants.INACTIVITY_EVENT, NotificationRuleTriggerType.DEVICE_INACTIVITY,
DataConstants.ENTITY_CREATED, NotificationRuleTriggerType.ENTITY_ACTION,
DataConstants.ENTITY_UPDATED, NotificationRuleTriggerType.ENTITY_ACTION,
DataConstants.ENTITY_DELETED, NotificationRuleTriggerType.ENTITY_ACTION
DataConstants.ENTITY_DELETED, NotificationRuleTriggerType.ENTITY_ACTION,
DataConstants.COMMENT_CREATED, NotificationRuleTriggerType.ALARM_COMMENT,
DataConstants.COMMENT_UPDATED, NotificationRuleTriggerType.ALARM_COMMENT
);
@Override
@ -82,37 +87,51 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
return;
}
processTrigger(tenantId, triggerType, ruleEngineMsg.getOriginator(), ruleEngineMsg, false);
processTrigger(tenantId, triggerType, ruleEngineMsg.getOriginator(), ruleEngineMsg);
}
@Override
public void process(TenantId tenantId, Alarm alarm, boolean deleted) {
processTrigger(tenantId, NotificationRuleTriggerType.ALARM, alarm.getId(), alarm, deleted);
AlarmTriggerObject triggerObject = AlarmTriggerObject.builder()
.alarm(alarm)
.deleted(deleted)
.build();
processTrigger(tenantId, NotificationRuleTriggerType.ALARM, alarm.getId(), triggerObject);
}
@Override
public void process(TenantId tenantId, RuleChainId ruleChainId, EntityId componentId, String componentName, ComponentLifecycleEvent eventType, Exception error) {
RuleEngineComponentLifecycleEventTriggerObject triggerObject = RuleEngineComponentLifecycleEventTriggerObject.builder()
.ruleChainId(ruleChainId)
.componentId(componentId)
.componentName(componentName)
.eventType(eventType)
.error(error)
.build();
processTrigger(tenantId, NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, componentId, triggerObject);
}
private void processTrigger(TenantId tenantId, NotificationRuleTriggerType triggerType, EntityId originatorEntityId,
Object triggerObject, boolean triggerRemoved) {
private void processTrigger(TenantId tenantId, NotificationRuleTriggerType triggerType, EntityId originatorEntityId, Object triggerObject) {
ListenableFuture<List<NotificationRule>> rulesFuture = dbCallbackExecutor.submit(() -> {
return notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, triggerType);
});
DonAsynchron.withCallback(rulesFuture, rules -> {
for (NotificationRule rule : rules) {
notificationExecutor.submit(() -> {
processNotificationRule(rule, originatorEntityId, triggerObject, triggerRemoved);
processNotificationRule(rule, originatorEntityId, triggerObject);
});
}
}, e -> {});
}
private <T> void processNotificationRule(NotificationRule rule, EntityId originatorEntityId,
T triggerObject, boolean triggerRemoved) {
private void processNotificationRule(NotificationRule rule, EntityId originatorEntityId, Object triggerObject) {
NotificationRuleTriggerConfig triggerConfig = rule.getTriggerConfig();
log.debug("Processing notification rule '{}' for trigger type {}", rule.getName(), rule.getTriggerType());
if (triggerConfig.getTriggerType().isUpdatable()) {
List<NotificationRequest> notificationRequests = notificationRequestService.findNotificationRequestsByRuleIdAndOriginatorEntityId(rule.getTenantId(), rule.getId(), originatorEntityId);
if (!notificationRequests.isEmpty()) {
if (triggerRemoved || matchesClearRule(triggerObject, triggerConfig)) {
if (matchesClearRule(triggerObject, triggerConfig)) {
notificationRequests = notificationRequests.stream()
.filter(notificationRequest -> {
if (!notificationRequest.isSent()) {
@ -133,7 +152,6 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
NotificationInfo previousNotificationInfo = notificationRequest.getInfo();
if (!notificationInfo.equals(previousNotificationInfo)) {
notificationRequest.setInfo(notificationInfo);
// and make notifications unread ?
dbCallbackExecutor.submit(() -> {
notificationCenter.updateNotificationRequest(rule.getTenantId(), notificationRequest);
});

5
application/src/main/java/org/thingsboard/server/service/notification/rule/NotificationRuleProcessingService.java

@ -16,7 +16,10 @@
package org.thingsboard.server.service.notification.rule;
import org.thingsboard.server.common.data.alarm.Alarm;
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.msg.TbMsg;
public interface NotificationRuleProcessingService {
@ -25,4 +28,6 @@ public interface NotificationRuleProcessingService {
void process(TenantId tenantId, Alarm alarm, boolean deleted);
void process(TenantId tenantId, RuleChainId ruleChainId, EntityId componentId, String componentName, ComponentLifecycleEvent eventType, Exception error);
}

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

@ -0,0 +1,52 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.notification.rule.trigger;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.notification.info.AlarmCommentNotificationInfo;
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;
@Service
public class AlarmCommentTriggerProcessor implements NotificationRuleTriggerProcessor<TbMsg, AlarmCommentNotificationRuleTriggerConfig> {
@Override
public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) {
return ruleEngineMsg.getMetaData().getValue("comment") != null;
}
@Override
public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) {
AlarmComment comment = JacksonUtil.fromString(ruleEngineMsg.getMetaData().getValue("comment"), AlarmComment.class);
Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class);
return AlarmCommentNotificationInfo.builder()
.comment(comment.getComment().get("text").asText())
.alarmType(alarm.getType())
.alarmId(comment.getAlarmId().getId())
.build();
}
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ALARM_COMMENT;
}
}

24
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmNotificationRuleTriggerProcessor.java → application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.service.notification.rule.trigger;
import lombok.Builder;
import lombok.Data;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.alarm.Alarm;
@ -23,18 +25,24 @@ import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig;
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.service.notification.rule.trigger.AlarmTriggerProcessor.AlarmTriggerObject;
@Service
public class AlarmNotificationRuleTriggerProcessor implements NotificationRuleTriggerProcessor<Alarm, AlarmNotificationRuleTriggerConfig> {
public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor<AlarmTriggerObject, AlarmNotificationRuleTriggerConfig> {
@Override
public boolean matchesFilter(Alarm alarm, AlarmNotificationRuleTriggerConfig triggerConfig) {
public boolean matchesFilter(AlarmTriggerObject triggerObject, AlarmNotificationRuleTriggerConfig triggerConfig) {
Alarm alarm = triggerObject.getAlarm();
return (CollectionUtils.isEmpty(triggerConfig.getAlarmTypes()) || triggerConfig.getAlarmTypes().contains(alarm.getType())) &&
(CollectionUtils.isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity()));
}
@Override
public boolean matchesClearRule(Alarm alarm, AlarmNotificationRuleTriggerConfig triggerConfig) {
public boolean matchesClearRule(AlarmTriggerObject triggerObject, AlarmNotificationRuleTriggerConfig triggerConfig) {
if (triggerObject.isDeleted()) {
return true;
}
Alarm alarm = triggerObject.getAlarm();
ClearRule clearRule = triggerConfig.getClearRule();
if (clearRule != null) {
if (clearRule.getAlarmStatus() != null) {
@ -45,7 +53,8 @@ public class AlarmNotificationRuleTriggerProcessor implements NotificationRuleTr
}
@Override
public NotificationInfo constructNotificationInfo(Alarm alarm, AlarmNotificationRuleTriggerConfig triggerConfig) {
public NotificationInfo constructNotificationInfo(AlarmTriggerObject triggerObject, AlarmNotificationRuleTriggerConfig triggerConfig) {
Alarm alarm = triggerObject.getAlarm();
return AlarmNotificationInfo.builder()
.alarmId(alarm.getUuidId())
.alarmType(alarm.getType())
@ -61,4 +70,11 @@ public class AlarmNotificationRuleTriggerProcessor implements NotificationRuleTr
return NotificationRuleTriggerType.ALARM;
}
@Data
@Builder
public static class AlarmTriggerObject {
private final Alarm alarm;
private final boolean deleted;
}
}

2
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityNotificationRuleTriggerProcessor.java → application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java

@ -30,7 +30,7 @@ import org.thingsboard.server.service.profile.TbDeviceProfileCache;
@Service
@RequiredArgsConstructor
public class DeviceInactivityNotificationRuleTriggerProcessor implements NotificationRuleTriggerProcessor<TbMsg, DeviceInactivityNotificationRuleTriggerConfig> {
public class DeviceInactivityTriggerProcessor implements NotificationRuleTriggerProcessor<TbMsg, DeviceInactivityNotificationRuleTriggerConfig> {
private final TbDeviceProfileCache deviceProfileCache;

2
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionNotificationRuleTriggerProcessor.java → application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java

@ -28,7 +28,7 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.UUID;
@Service
public class EntityActionNotificationRuleTriggerProcessor implements NotificationRuleTriggerProcessor<TbMsg, EntityActionNotificationRuleTriggerConfig> {
public class EntityActionTriggerProcessor implements NotificationRuleTriggerProcessor<TbMsg, EntityActionNotificationRuleTriggerConfig> {
@Override
public boolean matchesFilter(TbMsg ruleEngineMsg, EntityActionNotificationRuleTriggerConfig triggerConfig) {

97
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java

@ -0,0 +1,97 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.notification.rule.trigger;
import lombok.Builder;
import lombok.Data;
import org.apache.commons.collections.CollectionUtils;
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 java.util.Optional;
import java.util.Set;
@Service
public class RuleEngineComponentLifecycleEventTriggerProcessor implements NotificationRuleTriggerProcessor<RuleEngineComponentLifecycleEventTriggerObject, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig> {
@Override
public boolean matchesFilter(RuleEngineComponentLifecycleEventTriggerObject triggerObject, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) {
if (CollectionUtils.isNotEmpty(triggerConfig.getRuleChains())) {
if (!triggerConfig.getRuleChains().contains(triggerObject.getRuleChainId().getId())) {
return false;
}
}
EntityType componentType = triggerObject.getComponentId().getEntityType();
Set<ComponentLifecycleEvent> trackedEvents;
boolean onlyFailures;
if (componentType == EntityType.RULE_CHAIN) {
trackedEvents = triggerConfig.getRuleChainEvents();
onlyFailures = triggerConfig.isOnlyRuleChainLifecycleFailures();
} else if (componentType == EntityType.RULE_NODE && triggerConfig.isTrackRuleNodeEvents()) {
trackedEvents = triggerConfig.getRuleNodeEvents();
onlyFailures = triggerConfig.isOnlyRuleNodeLifecycleFailures();
} else {
return false;
}
if (CollectionUtils.isEmpty(trackedEvents)) {
trackedEvents = Set.of(ComponentLifecycleEvent.STARTED, ComponentLifecycleEvent.UPDATED, ComponentLifecycleEvent.STOPPED);
}
if (!trackedEvents.contains(triggerObject.getEventType())) {
return false;
}
if (onlyFailures) {
return triggerObject.getError() != null;
}
return true;
}
@Override
public NotificationInfo constructNotificationInfo(RuleEngineComponentLifecycleEventTriggerObject triggerObject, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) {
return RuleEngineComponentLifecycleEventNotificationInfo.builder()
.ruleChainId(triggerObject.getRuleChainId())
.componentId(triggerObject.getComponentId())
.componentName(triggerObject.getComponentName())
.eventType(triggerObject.getEventType())
.error(Optional.ofNullable(triggerObject.getError()).map(Throwable::getMessage).orElse(null))
.build();
}
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT;
}
@Data
@Builder
public static class RuleEngineComponentLifecycleEventTriggerObject {
private final RuleChainId ruleChainId;
private final EntityId componentId;
private final String componentName;
private final ComponentLifecycleEvent eventType;
private final Exception error;
}
}

10
application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java

@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.alarm.AlarmQuery;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
@ -49,6 +50,7 @@ import org.thingsboard.server.dao.alarm.AlarmOperationResult;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService;
import org.thingsboard.server.service.subscription.SubscriptionManagerService;
import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
@ -64,7 +66,7 @@ import java.util.Optional;
public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService implements AlarmSubscriptionService {
private final AlarmService alarmService;
private final AlarmCommentService alarmCommentService;
private final TbAlarmCommentService alarmCommentService;
private final TbApiUsageReportClient apiUsageClient;
private final TbApiUsageStateService apiUsageStateService;
@ -85,7 +87,11 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService
.type(AlarmCommentType.SYSTEM)
.comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm severity was updated from %s to %s", oldSeverity, result.getAlarm().getSeverity())))
.build();
alarmCommentService.createOrUpdateAlarmComment(alarm.getTenantId(), alarmComment);
try {
alarmCommentService.saveAlarmComment(alarm, alarmComment, null);
} catch (ThingsboardException e) {
log.error("Failed to save alarm comment", e);
}
}
}
if (result.isCreated()) {

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

@ -75,6 +75,8 @@ public class DataConstants {
public static final String ALARM_ACK = "ALARM_ACK";
public static final String ALARM_CLEAR = "ALARM_CLEAR";
public static final String ALARM_DELETE = "ALARM_DELETE";
public static final String COMMENT_CREATED = "COMMENT_CREATED";
public static final String COMMENT_UPDATED = "COMMENT_UPDATED";
public static final String ENTITY_ASSIGNED_FROM_TENANT = "ENTITY_ASSIGNED_FROM_TENANT";
public static final String ENTITY_ASSIGNED_TO_TENANT = "ENTITY_ASSIGNED_TO_TENANT";
public static final String PROVISION_SUCCESS = "PROVISION_SUCCESS";

32
common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java

@ -15,6 +15,9 @@
*/
package org.thingsboard.server.common.data.notification;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.google.common.base.Strings;
import lombok.Builder;
import lombok.Getter;
@ -22,7 +25,6 @@ import org.apache.commons.lang3.StringUtils;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.info.AlarmNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.settings.NotificationDeliveryMethodConfig;
@ -31,10 +33,12 @@ import org.thingsboard.server.common.data.notification.template.DeliveryMethodNo
import org.thingsboard.server.common.data.notification.template.HasSubject;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
import org.thingsboard.server.common.data.notification.template.PushDeliveryMethodNotificationTemplate;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@SuppressWarnings("unchecked")
@ -89,7 +93,7 @@ public class NotificationProcessingContext {
return (C) settings.getDeliveryMethodsConfigs().get(deliveryMethod);
}
public <T extends DeliveryMethodNotificationTemplate> T getProcessedTemplate(NotificationDeliveryMethod deliveryMethod, Map<String, String> templateContext) {
public <T extends DeliveryMethodNotificationTemplate> T getProcessedTemplate(NotificationDeliveryMethod deliveryMethod, Map<String, String> templateContext) {
if (request.getInfo() != null && deliveryMethod != NotificationDeliveryMethod.PUSH) { // for push notifications we are processing template from info on each serialization
templateContext = new HashMap<>(templateContext);
templateContext.putAll(request.getInfo().getTemplateData());
@ -101,14 +105,30 @@ public class NotificationProcessingContext {
String subject = ((HasSubject) template).getSubject();
((HasSubject) template).setSubject(processTemplate(subject, templateContext));
}
if (deliveryMethod == NotificationDeliveryMethod.PUSH) {
PushDeliveryMethodNotificationTemplate pushNotificationTemplate = (PushDeliveryMethodNotificationTemplate) template;
Optional<ObjectNode> buttonConfig = Optional.ofNullable(pushNotificationTemplate.getAdditionalConfig())
.map(config -> config.get("actionButtonConfig")).filter(JsonNode::isObject)
.map(config -> (ObjectNode) config);
if (buttonConfig.isPresent()) {
JsonNode link = buttonConfig.get().get("link");
if (link != null && link.isTextual()) {
link = new TextNode(processTemplate(link.asText(), templateContext, request.getInfo().getTemplateData()));
buttonConfig.get().set("link", link);
}
}
}
return template;
}
private static String processTemplate(String template, Map<String, String> context) {
if (template == null || context.isEmpty()) return template;
private static String processTemplate(String template, Map<String, String>... contexts) {
if (template == null) return null;
String result = template;
for (Map.Entry<String, String> kv : context.entrySet()) {
result = result.replace("${" + kv.getKey() + '}', kv.getValue());
for (Map<String, String> context : contexts) {
for (Map.Entry<String, String> kv : context.entrySet()) {
result = result.replace("${" + kv.getKey() + '}', kv.getValue());
}
}
return result;
}

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java

@ -20,6 +20,8 @@ public enum NotificationType {
GENERAL,
ALARM,
DEVICE_INACTIVITY,
ENTITY_ACTION;
ENTITY_ACTION,
ALARM_COMMENT,
RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT
}

45
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java

@ -0,0 +1,45 @@
/**
* Copyright © 2016-2022 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.info;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
import java.util.UUID;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AlarmCommentNotificationInfo implements NotificationInfo {
private String comment;
private String alarmType;
private UUID alarmId;
@Override
public Map<String, String> getTemplateData() {
return Map.of(
"comment", comment,
"alarmType", alarmType,
"alarmId", alarmId.toString()
);
}
}

2
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java

@ -51,7 +51,7 @@ public class EntityActionNotificationInfo implements RuleOriginatedNotificationI
"entityType", entityType.name(),
"entityId", entityId.toString(),
"entityName", entityName,
"actionType", actionType.name(),
"actionType", actionType.name().toLowerCase(),
"originatorUserId", originatorUserId.toString(),
"originatorUserName", originatorUserName
);

54
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java

@ -0,0 +1,54 @@
/**
* Copyright © 2016-2022 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.info;
import com.google.common.base.Strings;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import java.util.Map;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class RuleEngineComponentLifecycleEventNotificationInfo implements NotificationInfo {
private RuleChainId ruleChainId;
private EntityId componentId;
private String componentName;
private ComponentLifecycleEvent eventType;
private String error;
// TODO: add rule chain name
@Override
public Map<String, String> getTemplateData() {
return Map.of(
"ruleChainId", ruleChainId.toString(),
"componentId", componentId.toString(),
"componentType", componentId.getEntityType().name(),
"componentName", componentName,
"eventType", eventType.name(),
"error", Strings.nullToEmpty(error)
);
}
}

28
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java

@ -0,0 +1,28 @@
/**
* Copyright © 2016-2022 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.Data;
@Data
public class AlarmCommentNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ALARM_COMMENT;
}
}

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java

@ -25,7 +25,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonSubTypes({
@Type(value = AlarmNotificationRuleTriggerConfig.class, name = "ALARM"),
@Type(value = DeviceInactivityNotificationRuleTriggerConfig.class, name = "DEVICE_INACTIVITY"),
@Type(value = EntityActionNotificationRuleTriggerConfig.class, name = "ENTITY_ACTION")
@Type(value = EntityActionNotificationRuleTriggerConfig.class, name = "ENTITY_ACTION"),
@Type(value = AlarmCommentNotificationRuleTriggerConfig.class, name = "ALARM_COMMENT"),
@Type(value = RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.class, name = "RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT")
})
public interface NotificationRuleTriggerConfig {

6
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java

@ -22,10 +22,12 @@ import lombok.RequiredArgsConstructor;
public enum NotificationRuleTriggerType {
ALARM(true),
ALARM_COMMENT(true),
DEVICE_INACTIVITY(false),
ENTITY_ACTION(false);
ENTITY_ACTION(false),
RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT(false);
@Getter
private final boolean isUpdatable;
private final boolean updatable;
}

41
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.java

@ -0,0 +1,41 @@
/**
* Copyright © 2016-2022 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.Data;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import java.util.Set;
import java.util.UUID;
@Data
public class RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig {
private Set<ComponentLifecycleEvent> ruleChainEvents; // available options: STARTED, UPDATED, STOPPED. if empty - all events
private boolean onlyRuleChainLifecycleFailures;
private boolean trackRuleNodeEvents;
private Set<ComponentLifecycleEvent> ruleNodeEvents; // available options: STARTED, UPDATED, STOPPED. if empty - all events
private boolean onlyRuleNodeLifecycleFailures;
private Set<UUID> ruleChains; // if empty - all rule chains
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT;
}
}

4
dao/src/main/resources/sql/schema-entities.sql

@ -807,7 +807,7 @@ CREATE TABLE IF NOT EXISTS notification_template (
created_time BIGINT NOT NULL,
tenant_id UUID NULL CONSTRAINT fk_notification_template_tenant_id REFERENCES tenant(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
notification_type VARCHAR(32) NOT NULL,
notification_type VARCHAR(50) NOT NULL,
configuration VARCHAR(10000) NOT NULL,
CONSTRAINT uq_notification_template_name UNIQUE (tenant_id, name)
);
@ -845,7 +845,7 @@ CREATE TABLE IF NOT EXISTS notification (
created_time BIGINT NOT NULL,
request_id UUID NULL CONSTRAINT fk_notification_request_id REFERENCES notification_request(id) ON DELETE CASCADE,
recipient_id UUID NOT NULL CONSTRAINT fk_notification_recipient_id REFERENCES tb_user(id) ON DELETE CASCADE,
type VARCHAR(32) NOT NULL,
type VARCHAR(50) NOT NULL,
subject VARCHAR(255),
text VARCHAR(1000) NOT NULL,
additional_config VARCHAR(1000),

Loading…
Cancel
Save